kantox-roles 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,234 @@
1
+ module Kantox
2
+
3
+ # FMI: built-ins (fuck Thor, it’s so crypting)
4
+ # — *class_name* Todo
5
+ # — *plural_name* todos
6
+ # — *file_name* todo
7
+ class PunditPolicyGenerator < Rails::Generators::NamedBase
8
+ desc 'Creates new pundit policy in app/policies and specs for it'
9
+ source_root File.expand_path('../templates', __FILE__)
10
+
11
+ class_option :users, type: 'array', default: ['Administrator'], aliases: '-u',
12
+ desc: 'Select users allowed to this controller.'
13
+
14
+ def create_pundit_policy_file
15
+ invoke 'pundit:install' unless application_policy_exist?
16
+
17
+ wrn "Plural name of Model specified. Please review results carefully." if file_name == plural_name
18
+
19
+ (controller = check_controller! class_name).is_a?(Class) ?
20
+ nfo("Controller #{controller} to guard found successfully") :
21
+ err("Could not find the controller to create policy for (input: «#{class_name}»).")
22
+
23
+ (allowed = check_allowed! options['users']).is_a?(String) ?
24
+ err("Wrong user classes specified: #{allowed}.") :
25
+ nfo("Allowed users would be: #{allowed}")
26
+
27
+ methods = controller.instance_methods(false).reject do |im|
28
+ im.to_s =~ /\A∃|\A_callback_|\W\z/
29
+ end
30
+ scs "Everything looks fine. Will guard [#{controller}]; allow: #{allowed}; methods: #{methods}."
31
+
32
+ create_file "app/policies/#{file_name}_policy.rb",
33
+ tmpl_policy(class_name, policy_methods(methods, allowed), methods, allowed)
34
+
35
+ is_controller = controller <= ApplicationController ? controller : nil
36
+ create_file "spec/policies/#{file_name}_policy_spec.rb",
37
+ tmpl_policy_spec(
38
+ class_name,
39
+ spec_methods(methods, allowed),
40
+ controller_code(is_controller, class_name, methods, allowed)
41
+ )
42
+
43
+ yaml_methods = methods.map { |im| " '#{im}': :pundit" }.join($/)
44
+ create_file "strategies/#{file_name}.yml",
45
+ <<-FILE
46
+ '#{controller.name}' :
47
+ #{yaml_methods}
48
+ FILE
49
+ end
50
+
51
+ protected
52
+
53
+ SYMBOLS = { scs: ['107', '✔'], nfo: ['68', '✓'], wrn: ['226', '✗'], err: ['196', '✘'] }
54
+ def log msg
55
+ raise "Do not call log directly, use [err,wrn,nfo,scs].sample, you lame programmer!" unless cllr = caller(0)[1][/`(\w+)'/, 1]
56
+ sym = SYMBOLS[cllr.to_sym]
57
+ puts "\e[01;38;05;#{sym.first}m#{sym.last} kantox:pundit_policy\e[0m: #{msg}"
58
+ end
59
+
60
+ def err msg
61
+ log "#{msg}\nAborting...\n\n"
62
+ exit 1
63
+ end
64
+
65
+ def nfo msg
66
+ log msg
67
+ end
68
+
69
+ def wrn msg
70
+ log msg
71
+ end
72
+
73
+ def scs msg
74
+ log msg
75
+ end
76
+
77
+ def application_policy_exist?
78
+ File.exist? "#{Rails.root}/app/policies/application_policy.rb"
79
+ end
80
+
81
+ # for historical reasons this is called “check_controller,” while it currently simply finds a class, not necessarily a controller
82
+ def check_controller! name
83
+ variants = ['app/controllers/admin/', 'app/controllers/', 'app/datatables/'].product([name.tableize, name.tableize.singularize]).map &:join
84
+ controllers = variants.map do |v|
85
+ next nil unless (files = Dir["#{Rails.root}/#{v}*.rb"]).size > 0
86
+ require files.first
87
+ entity = files.first[/\A#{Rails.root}\/#{v}_?(.*)\.rb\z/, 1].camelize
88
+ c_name = "#{'Controller' == entity ? name.pluralize : name}#{entity}"
89
+ Admin.const_defined?(c_name) ?
90
+ Admin.const_get(c_name) :
91
+ (Kernel.const_defined?(c_name) ? Kernel.const_get(c_name) : nil)
92
+ end.compact
93
+ wrn "Was unable to find controller by name #{name}" if controllers.empty?
94
+ controllers.first
95
+ end
96
+
97
+ def check_allowed! users
98
+ allowed = users.select do |u|
99
+ begin
100
+ require "#{Rails.root}/app/models/#{u.underscore}.rb"
101
+ rescue LoadError => e
102
+ wrn e
103
+ end
104
+ Kernel.const_defined? u
105
+ end
106
+
107
+ (disallowed = users - allowed).empty? ? allowed : disallowed.inspect
108
+ end
109
+
110
+ def policy_methods mthds, allowed
111
+ # allowed here are already checked existing classes
112
+ mthds.map do |im| <<-FILE
113
+ # Checker for #{im} method. Allows access for [#{allowed.join(',')}]
114
+ # @return [TrueClass|FalseClass] true to allow access, false otherwise
115
+ # def #{im}?
116
+ # [#{allowed.join(', ')}].include? @user.class
117
+ # end
118
+ FILE
119
+ end.join($/).strip
120
+ end
121
+
122
+ def spec_methods mthds, allowed
123
+ allowed_steps = allowed.map do |a|
124
+ "# expect(subject).to permit(#{a}.new, nil)"
125
+ end.join("#{$/} ")
126
+ mthds.map do |im| <<-FILE
127
+ ## Permissions for #{im} method
128
+ # permissions :#{im}? do
129
+ # it "denies access if user is not allowed (not in [#{allowed.join(',')}])", :roles do
130
+ # expect(subject).not_to permit(User.new, nil)
131
+ # end
132
+ #
133
+ # it "grants access if user is allowed (one of [#{allowed.join(',')}])", :roles do
134
+ #{allowed_steps}
135
+ # end
136
+ # end
137
+ FILE
138
+ end.join($/).strip
139
+ end
140
+
141
+ def controller_code controller, klazz, mthds, allowed
142
+ return '' if controller.nil? # FIXME Handle let(...) below properly and reenable!!
143
+
144
+ mthds.map do |im| <<-FILE
145
+ # describe #{controller}, :type => :controller do
146
+ # include AuthorizationHelper
147
+ #
148
+ # subject { Kantox::Policies::#{klazz}Policy }
149
+ #
150
+ # describe :#{im} do
151
+ # context('#{klazz} @ #{controller}') do
152
+ # let(:workflow_state) { 'preapproved' }
153
+ # let(:profile) { create(:profile, workflow_state: workflow_state, telephone: '12345678') }
154
+ # let(:client) { create(:client, roles: [Role.poster], profiles: [profile]) }
155
+ # before do
156
+ # flexmock(controller, current_user: user)
157
+ # get :#{im}, params(profile_id: profile.id, client_id: client.id, format: :json)
158
+ # end
159
+ #
160
+ # users = [
161
+ # [#{allowed.join(', ')}],
162
+ # [User]
163
+ # ].zip [200, 403]
164
+ #
165
+ # users.each do |users, code|
166
+ # users.each do |user|
167
+ # context("for \#{user.name}") do
168
+ # let(:user) { user.new }
169
+ # it { response.status.should == code }
170
+ # end
171
+ # end
172
+ # end
173
+ # end
174
+ # end
175
+ # end
176
+ FILE
177
+ end.join($/).strip
178
+ end
179
+
180
+ def tmpl_policy klazz, mthds_code, mthds, allowed
181
+ mthds_joined = mthds.map { |m| ":#{m}?" }.join ', '
182
+ <<-FILE
183
+ module Kantox
184
+ module Policies
185
+ class #{klazz}Policy < ApplicationPolicy
186
+ ALLOWED = lambda do |type|
187
+ case type
188
+ when :read then [#{allowed.join(', ')}]
189
+ when :write then []
190
+ end
191
+ end
192
+ # Split methods according to roles above
193
+ METHODS = {
194
+ read: [#{mthds_joined}],
195
+ write: []
196
+ }
197
+
198
+
199
+ ############################################################################
200
+ ### The methods below are just stubs for exotic handlers.
201
+ ### Uncomment those you want to behave in specific manner.
202
+ ############################################################################
203
+
204
+ #{mthds_code}
205
+ end
206
+ end
207
+ end
208
+ FILE
209
+ end
210
+
211
+ def tmpl_policy_spec klazz, mthds, controller_code
212
+ <<-FILE
213
+ require 'spec_helper'
214
+
215
+ examples_for_policy Kantox::Policies::#{klazz}Policy
216
+
217
+
218
+ ############################################################################
219
+ ### The methods below are just stubs for exotic handlers.
220
+ ### Uncomment those you want to behave in specific manner.
221
+ ############################################################################
222
+
223
+ # describe Kantox::Policies::#{klazz}Policy do
224
+
225
+ # subject { Kantox::Policies::#{klazz}Policy }
226
+
227
+ #{mthds}
228
+ # end
229
+
230
+ #{controller_code}
231
+ FILE
232
+ end
233
+ end
234
+ end
metadata ADDED
@@ -0,0 +1,178 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kantox-roles
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.2.1
5
+ platform: ruby
6
+ authors:
7
+ - Kantox LTD
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-10-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: hashie
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: pundit
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.7'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.7'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.10'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.10'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '2.12'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '2.12'
97
+ - !ruby/object:Gem::Dependency
98
+ name: cucumber
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1.3'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '1.3'
111
+ - !ruby/object:Gem::Dependency
112
+ name: yard
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
+ description: Roles Management interface for virtually every backend, mostly like OmniAuth
126
+ for authentication
127
+ email:
128
+ - aleksei.matiushkin@kantox.com
129
+ executables: []
130
+ extensions: []
131
+ extra_rdoc_files: []
132
+ files:
133
+ - ".gitignore"
134
+ - ".rspec"
135
+ - ".travis.yml"
136
+ - Gemfile
137
+ - README.md
138
+ - Rakefile
139
+ - bin/console
140
+ - bin/setup
141
+ - kantox-roles.gemspec
142
+ - lib/kantox/roles.rb
143
+ - lib/kantox/roles/helpers.rb
144
+ - lib/kantox/roles/logger.rb
145
+ - lib/kantox/roles/strategies/aspect.rb
146
+ - lib/kantox/roles/strategies/cancancan.rb
147
+ - lib/kantox/roles/strategies/pundit.rb
148
+ - lib/kantox/roles/strategies/strategy_error.rb
149
+ - lib/kantox/roles/strategies/wrapper.rb
150
+ - lib/kantox/roles/version.rb
151
+ - lib/rails/generators/kantox/policy_spec_helper.rb.tmpl
152
+ - lib/rails/generators/kantox/pundit_policy_generator.rb
153
+ homepage: http://kantox.com
154
+ licenses:
155
+ - Kantox LTD Commercial
156
+ metadata: {}
157
+ post_install_message:
158
+ rdoc_options: []
159
+ require_paths:
160
+ - lib
161
+ required_ruby_version: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - "~>"
164
+ - !ruby/object:Gem::Version
165
+ version: '2.1'
166
+ required_rubygems_version: !ruby/object:Gem::Requirement
167
+ requirements:
168
+ - - ">="
169
+ - !ruby/object:Gem::Version
170
+ version: '0'
171
+ requirements: []
172
+ rubyforge_project:
173
+ rubygems_version: 2.4.8
174
+ signing_key:
175
+ specification_version: 4
176
+ summary: OmniRoles mechanism for Kantox Role Management
177
+ test_files: []
178
+ has_rdoc: