rhino_project_core 0.20.0.alpha.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (134) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +28 -0
  4. data/Rakefile +35 -0
  5. data/app/assets/stripe_flow.png +0 -0
  6. data/app/controllers/concerns/rhino/authenticated.rb +18 -0
  7. data/app/controllers/concerns/rhino/error_handling.rb +60 -0
  8. data/app/controllers/concerns/rhino/paper_trail_whodunnit.rb +11 -0
  9. data/app/controllers/concerns/rhino/permit.rb +38 -0
  10. data/app/controllers/concerns/rhino/set_current_user.rb +13 -0
  11. data/app/controllers/rhino/account_controller.rb +34 -0
  12. data/app/controllers/rhino/active_model_extension_controller.rb +52 -0
  13. data/app/controllers/rhino/base_controller.rb +23 -0
  14. data/app/controllers/rhino/crud_controller.rb +57 -0
  15. data/app/controllers/rhino/simple_controller.rb +13 -0
  16. data/app/controllers/rhino/simple_stream_controller.rb +12 -0
  17. data/app/helpers/rhino/omniauth_helper.rb +67 -0
  18. data/app/helpers/rhino/policy_helper.rb +42 -0
  19. data/app/helpers/rhino/segment_helper.rb +62 -0
  20. data/app/models/rhino/account.rb +13 -0
  21. data/app/models/rhino/current.rb +7 -0
  22. data/app/models/rhino/user.rb +44 -0
  23. data/app/overrides/active_record/autosave_association_override.rb +18 -0
  24. data/app/overrides/active_record/delegated_type_override.rb +14 -0
  25. data/app/overrides/activestorage/direct_uploads_controller_override.rb +23 -0
  26. data/app/overrides/activestorage/redirect_controller_override.rb +21 -0
  27. data/app/overrides/activestorage/redirect_representation_controller_override.rb +21 -0
  28. data/app/overrides/devise_token_auth/confirmations_controller_override.rb +14 -0
  29. data/app/overrides/devise_token_auth/omniauth_callbacks_controller_override.rb +45 -0
  30. data/app/overrides/devise_token_auth/passwords_controller_override.rb +9 -0
  31. data/app/overrides/devise_token_auth/registrations_controller_override.rb +20 -0
  32. data/app/overrides/devise_token_auth/sessions_controller_override.rb +26 -0
  33. data/app/overrides/devise_token_auth/token_validations_controller_override.rb +18 -0
  34. data/app/policies/rhino/account_policy.rb +27 -0
  35. data/app/policies/rhino/active_storage_attachment_policy.rb +16 -0
  36. data/app/policies/rhino/admin_policy.rb +20 -0
  37. data/app/policies/rhino/base_policy.rb +72 -0
  38. data/app/policies/rhino/crud_policy.rb +109 -0
  39. data/app/policies/rhino/editor_policy.rb +12 -0
  40. data/app/policies/rhino/global_policy.rb +8 -0
  41. data/app/policies/rhino/resource_info_policy.rb +9 -0
  42. data/app/policies/rhino/user_policy.rb +20 -0
  43. data/app/policies/rhino/viewer_policy.rb +19 -0
  44. data/app/resources/rhino/info_graph.rb +41 -0
  45. data/app/resources/rhino/open_api_info.rb +108 -0
  46. data/config/routes.rb +19 -0
  47. data/db/migrate/20180101000000_devise_token_auth_create_users.rb +54 -0
  48. data/db/migrate/20180622142754_add_allow_change_password_to_users.rb +5 -0
  49. data/db/migrate/20191217010224_add_approved_to_users.rb +7 -0
  50. data/db/migrate/20200503182019_change_tokens_to_json_b.rb +9 -0
  51. data/lib/commands/rhino/module/coverage_command.rb +44 -0
  52. data/lib/commands/rhino/module/dummy_command.rb +43 -0
  53. data/lib/commands/rhino/module/new_command.rb +34 -0
  54. data/lib/commands/rhino/module/rails_command.rb +43 -0
  55. data/lib/commands/rhino/module/test_command.rb +43 -0
  56. data/lib/generators/rhino/dev/setup/setup_generator.rb +199 -0
  57. data/lib/generators/rhino/dev/setup/templates/env.client.tt +4 -0
  58. data/lib/generators/rhino/dev/setup/templates/env.root.tt +1 -0
  59. data/lib/generators/rhino/dev/setup/templates/env.server.tt +35 -0
  60. data/lib/generators/rhino/dev/setup/templates/prepare-commit-msg +17 -0
  61. data/lib/generators/rhino/install/install_generator.rb +24 -0
  62. data/lib/generators/rhino/install/templates/account.rb +4 -0
  63. data/lib/generators/rhino/install/templates/rhino.rb +24 -0
  64. data/lib/generators/rhino/install/templates/user.rb +4 -0
  65. data/lib/generators/rhino/model/model_generator.rb +96 -0
  66. data/lib/generators/rhino/module/USAGE +6 -0
  67. data/lib/generators/rhino/module/module_generator.rb +92 -0
  68. data/lib/generators/rhino/module/templates/%name%.gemspec.tt +24 -0
  69. data/lib/generators/rhino/module/templates/lib/%namespaced_name%/engine.rb.tt +18 -0
  70. data/lib/generators/rhino/module/templates/lib/generators/%namespaced_name%/install/install_generator.rb.tt +12 -0
  71. data/lib/generators/rhino/module/templates/lib/tasks/%namespaced_name%_tasks.rake.tt +13 -0
  72. data/lib/generators/rhino/module/templates/test/dummy/app/models/user.rb +4 -0
  73. data/lib/generators/rhino/module/templates/test/dummy/config/database.yml +25 -0
  74. data/lib/generators/rhino/module/templates/test/dummy/config/initializers/devise.rb +311 -0
  75. data/lib/generators/rhino/module/templates/test/dummy/config/initializers/devise_token_auth.rb +71 -0
  76. data/lib/generators/rhino/module/templates/test/test_helper.rb +54 -0
  77. data/lib/generators/rhino/policy/policy_generator.rb +33 -0
  78. data/lib/generators/rhino/policy/templates/policy.rb.tt +46 -0
  79. data/lib/generators/test_unit/rhino_policy_generator.rb +13 -0
  80. data/lib/generators/test_unit/templates/policy_test.rb.tt +57 -0
  81. data/lib/rhino/engine.rb +166 -0
  82. data/lib/rhino/omniauth/strategies/azure_o_auth2.rb +16 -0
  83. data/lib/rhino/resource/active_model_extension/backing_store/google_sheet.rb +89 -0
  84. data/lib/rhino/resource/active_model_extension/backing_store.rb +33 -0
  85. data/lib/rhino/resource/active_model_extension/describe.rb +38 -0
  86. data/lib/rhino/resource/active_model_extension/params.rb +70 -0
  87. data/lib/rhino/resource/active_model_extension/properties.rb +231 -0
  88. data/lib/rhino/resource/active_model_extension/reference.rb +50 -0
  89. data/lib/rhino/resource/active_model_extension/routing.rb +15 -0
  90. data/lib/rhino/resource/active_model_extension/serialization.rb +16 -0
  91. data/lib/rhino/resource/active_model_extension.rb +38 -0
  92. data/lib/rhino/resource/active_record_extension/describe.rb +44 -0
  93. data/lib/rhino/resource/active_record_extension/params.rb +213 -0
  94. data/lib/rhino/resource/active_record_extension/properties.rb +85 -0
  95. data/lib/rhino/resource/active_record_extension/properties_describe.rb +228 -0
  96. data/lib/rhino/resource/active_record_extension/reference.rb +50 -0
  97. data/lib/rhino/resource/active_record_extension/routing.rb +21 -0
  98. data/lib/rhino/resource/active_record_extension/search.rb +23 -0
  99. data/lib/rhino/resource/active_record_extension/serialization.rb +16 -0
  100. data/lib/rhino/resource/active_record_extension/super_admin.rb +25 -0
  101. data/lib/rhino/resource/active_record_extension.rb +32 -0
  102. data/lib/rhino/resource/active_record_tree.rb +50 -0
  103. data/lib/rhino/resource/active_storage_extension.rb +41 -0
  104. data/lib/rhino/resource/describe.rb +19 -0
  105. data/lib/rhino/resource/owner.rb +172 -0
  106. data/lib/rhino/resource/params.rb +31 -0
  107. data/lib/rhino/resource/properties.rb +192 -0
  108. data/lib/rhino/resource/reference.rb +29 -0
  109. data/lib/rhino/resource/routing.rb +107 -0
  110. data/lib/rhino/resource/serialization.rb +13 -0
  111. data/lib/rhino/resource/sieves.rb +36 -0
  112. data/lib/rhino/resource.rb +55 -0
  113. data/lib/rhino/sieve/filter.rb +149 -0
  114. data/lib/rhino/sieve/geospatial.rb +45 -0
  115. data/lib/rhino/sieve/helpers.rb +11 -0
  116. data/lib/rhino/sieve/limit.rb +20 -0
  117. data/lib/rhino/sieve/offset.rb +16 -0
  118. data/lib/rhino/sieve/order.rb +143 -0
  119. data/lib/rhino/sieve/search.rb +20 -0
  120. data/lib/rhino/sieve.rb +159 -0
  121. data/lib/rhino/test_case/controller.rb +145 -0
  122. data/lib/rhino/test_case/model.rb +86 -0
  123. data/lib/rhino/test_case/override.rb +19 -0
  124. data/lib/rhino/test_case/policy.rb +76 -0
  125. data/lib/rhino/test_case.rb +11 -0
  126. data/lib/rhino/version.rb +17 -0
  127. data/lib/rhino_project_core.rb +131 -0
  128. data/lib/tasks/rhino.rake +24 -0
  129. data/lib/tasks/rhino_dev.rake +17 -0
  130. data/lib/validators/country_validator.rb +11 -0
  131. data/lib/validators/email_validator.rb +8 -0
  132. data/lib/validators/ipv4_validator.rb +10 -0
  133. data/lib/validators/mac_address_validator.rb +9 -0
  134. metadata +531 -0
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ # correction for nested forms errors indexation
4
+ # this correction is still necessary in rails 7.0
5
+ module ActiveRecord::AutosaveAssociation
6
+ private
7
+ def validate_collection_association(reflection)
8
+ return unless (association = association_instance_get(reflection.name))
9
+
10
+ return unless (records = associated_records_to_validate_or_save(association, new_record?, reflection.options[:autosave]))
11
+
12
+ all_records = association.target.find_all
13
+ records.each do |record|
14
+ index = all_records.find_index(record)
15
+ association_valid?(reflection, record, index)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ # correction for nested forms errors indexation
4
+ # this correction is still necessary in rails 7.0
5
+ module ActiveRecord::DelegatedType
6
+ def delegated_type(role, types:, **options)
7
+ belongs_to role, options.delete(:scope), **options.merge(polymorphic: true)
8
+ define_delegated_type_methods(role, types:, options:)
9
+
10
+ define_singleton_method "#{role}_types" do
11
+ types.map(&:to_s)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ # https://stackoverflow.com/questions/4470108/when-monkey-patching-an-instance-method-can-you-call-the-overridden-method-from/4471202
4
+ # Mixin Prepending
5
+ module ActiveStorage::DirectUploadsController::Extensions
6
+ def create
7
+ authorize ActiveStorage::Attachment
8
+
9
+ super
10
+ end
11
+ end
12
+
13
+ class ActiveStorage::DirectUploadsController
14
+ include DeviseTokenAuth::Concerns::SetUserByToken
15
+ include Pundit
16
+
17
+ include Rhino::ErrorHandling
18
+ include Rhino::Authenticated
19
+
20
+ after_action :verify_authorized
21
+
22
+ prepend ActiveStorage::DirectUploadsController::Extensions
23
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveStorage::Blobs::RedirectController::Extensions
4
+ def show
5
+ authorize ActiveStorage::Attachment
6
+
7
+ super
8
+ end
9
+ end
10
+
11
+ class ActiveStorage::Blobs::RedirectController
12
+ include DeviseTokenAuth::Concerns::SetUserByToken
13
+ include Pundit
14
+
15
+ include Rhino::ErrorHandling
16
+ include Rhino::Authenticated
17
+
18
+ after_action :verify_authorized
19
+
20
+ prepend ActiveStorage::Blobs::RedirectController::Extensions
21
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveStorage::Representations::RedirectController::Extensions
4
+ def show
5
+ authorize ActiveStorage::Attachment
6
+
7
+ super
8
+ end
9
+ end
10
+
11
+ class ActiveStorage::Representations::RedirectController
12
+ include DeviseTokenAuth::Concerns::SetUserByToken
13
+ include Pundit
14
+
15
+ include Rhino::ErrorHandling
16
+ include Rhino::Authenticated
17
+
18
+ after_action :verify_authorized
19
+
20
+ prepend ActiveStorage::Representations::RedirectController::Extensions
21
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DeviseTokenAuth::ConfirmationsController::Extensions
4
+ # devise_token_auth raises an error if the confirmation token can't be found
5
+ def show
6
+ super
7
+ rescue StandardError
8
+ redirect_to ENV["FRONT_END_URL"]
9
+ end
10
+ end
11
+
12
+ class DeviseTokenAuth::ConfirmationsController
13
+ prepend DeviseTokenAuth::ConfirmationsController::Extensions
14
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ # https://stackoverflow.com/questions/4470108/when-monkey-patching-an-instance-method-can-you-call-the-overridden-method-from/4471202
4
+ # Mixin Prepending
5
+ module DeviseTokenAuth::OmniauthCallbacksController::Extensions
6
+ include RhinoOrganizations::Concerns::CreateOrganization if Rhino.resources.include?("Organization")
7
+
8
+ def redirect_callbacks
9
+ # derive target redirect route from 'resource_class' param, which was set
10
+ # before authentication.
11
+ devise_mapping = get_devise_mapping
12
+ redirect_route = get_redirect_route(devise_mapping)
13
+
14
+ # preserve omniauth info for success route. ignore 'extra' in twitter
15
+ # and 'credentials' in others auth response, like azure_oauth2, to avoid CookieOverflow.
16
+
17
+ session["dta.omniauth.auth"] = request.env["omniauth.auth"].except("extra").except("credentials")
18
+ session["dta.omniauth.params"] = request.env["omniauth.params"]
19
+
20
+ redirect_to redirect_route
21
+ end
22
+
23
+ def omniauth_success
24
+ super do |resource|
25
+ if Rhino.resources.include?("Organization") && @oauth_registration
26
+ # Create if this is the first time we've seen the user
27
+ create_organization(resource)
28
+ end
29
+ end
30
+
31
+ # set a server cookie if configured
32
+ if DeviseTokenAuth.cookie_enabled
33
+ auth_header = @resource.build_auth_headers(@token.token, @token.client)
34
+ cookies[DeviseTokenAuth.cookie_name] = DeviseTokenAuth.cookie_attributes.merge(value: auth_header.to_json)
35
+ end
36
+ rescue ActiveRecord::RecordInvalid
37
+ # Technically this could be something else, but this is the most common
38
+ # devise_token_auth calls save! which is why we catch it here
39
+ render_data_or_redirect("authFailure", error: "Email address in use")
40
+ end
41
+ end
42
+
43
+ class DeviseTokenAuth::OmniauthCallbacksController
44
+ prepend DeviseTokenAuth::OmniauthCallbacksController::Extensions
45
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class DeviseTokenAuth::PasswordsController
4
+ # If there is an error preparing to edit the password, redirect to frontend
5
+ # This would normally be an expired password token
6
+ def render_edit_error
7
+ redirect_to "#{ENV['FRONT_END_URL']}/auth/reset-password/expired"
8
+ end
9
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ # https://stackoverflow.com/questions/4470108/when-monkey-patching-an-instance-method-can-you-call-the-overridden-method-from/4471202
4
+ # Mixin Prepending
5
+ module DeviseTokenAuth::RegistrationsController::Extensions
6
+ include RhinoOrganizations::Concerns::CreateOrganization if Rhino.resources.include?("Organization")
7
+
8
+ def create
9
+ return render_error(401, "signup is not allowed") unless Rhino.allow_signup
10
+
11
+ super do |resource|
12
+ # Create if this is the first time we've seen the user
13
+ create_organization(resource) if Rhino.resources.include?("Organization")
14
+ end
15
+ end
16
+ end
17
+
18
+ class DeviseTokenAuth::RegistrationsController
19
+ prepend DeviseTokenAuth::RegistrationsController::Extensions
20
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DeviseTokenAuth::SessionsController::Extensions
4
+ def render_destroy_error
5
+ if DeviseTokenAuth.cookie_enabled
6
+ # If a cookie is set with a domain specified then it must be deleted with that domain specified
7
+ # See https://api.rubyonrails.org/classes/ActionDispatch/Cookies.html
8
+ cookies.delete(DeviseTokenAuth.cookie_name, domain: DeviseTokenAuth.cookie_attributes[:domain])
9
+ end
10
+ super
11
+ end
12
+
13
+ def create
14
+ super
15
+ Rhino::SegmentHelper.track("Signed In", @resource) unless @resource.nil?
16
+ end
17
+
18
+ def destroy
19
+ Rhino::SegmentHelper.track("Signed Out", @resource) unless @resource.nil?
20
+ super
21
+ end
22
+ end
23
+
24
+ class DeviseTokenAuth::SessionsController
25
+ prepend DeviseTokenAuth::SessionsController::Extensions
26
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ # https://stackoverflow.com/questions/4470108/when-monkey-patching-an-instance-method-can-you-call-the-overridden-method-from/4471202
4
+ # Mixin Prepending
5
+ module DeviseTokenAuth::TokenValidationsController::Extensions
6
+ def render_validate_token_error
7
+ if DeviseTokenAuth.cookie_enabled
8
+ # If a cookie is set with a domain specified then it must be deleted with that domain specified
9
+ # See https://api.rubyonrails.org/classes/ActionDispatch/Cookies.html
10
+ cookies.delete(DeviseTokenAuth.cookie_name, domain: DeviseTokenAuth.cookie_attributes[:domain])
11
+ end
12
+ super
13
+ end
14
+ end
15
+
16
+ class DeviseTokenAuth::TokenValidationsController
17
+ prepend DeviseTokenAuth::TokenValidationsController::Extensions
18
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rhino
4
+ class AccountPolicy < ::Rhino::BasePolicy
5
+ # Show and update only for this user
6
+ # It should only ever be current user, but this is a safety check
7
+
8
+ def show?
9
+ authorize_action(auth_owned?)
10
+ end
11
+
12
+ def update?
13
+ authorize_action(auth_owned?)
14
+ end
15
+
16
+ class Scope < ::Rhino::BasePolicy::Scope
17
+ def resolve
18
+ scope.where(id: auth_owner&.id)
19
+ end
20
+ end
21
+
22
+ private
23
+ def auth_owned?
24
+ record.is_a?(User) && record&.id == auth_owner&.id
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rhino
4
+ class ActiveStorageAttachmentPolicy < ::Rhino::BasePolicy
5
+ def create?
6
+ authorize_action(true)
7
+ end
8
+
9
+ def show?
10
+ authorize_action(true)
11
+ end
12
+
13
+ class Scope < ::Rhino::BasePolicy::Scope
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rhino
4
+ class AdminPolicy < ::Rhino::ViewerPolicy
5
+ def create?
6
+ authorize_action(true)
7
+ end
8
+
9
+ def update?
10
+ authorize_action(true)
11
+ end
12
+
13
+ def destroy?
14
+ authorize_action(true)
15
+ end
16
+
17
+ class Scope < ::Rhino::ViewerPolicy::Scope
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Base policy allows no actions by default
4
+ # Permitted attributes are the default not empty set though
5
+ module Rhino
6
+ class BasePolicy
7
+ include ActiveSupport::Callbacks
8
+
9
+ # Do not authorize if any before callbacks return false
10
+ define_callbacks :authorize_action, terminator: ->(_target, result_lambda) { result_lambda.call == false }
11
+
12
+ attr_reader :auth_owner, :record
13
+
14
+ def initialize(auth_owner, record)
15
+ @auth_owner = auth_owner
16
+ @record = record
17
+ end
18
+
19
+ # Authorize the action with a default permission
20
+ # Ensure the callbacks are run
21
+ def authorize_action(permission)
22
+ run_callbacks :authorize_action do
23
+ permission
24
+ end
25
+ end
26
+
27
+ def index?
28
+ authorize_action(false)
29
+ end
30
+
31
+ def show?
32
+ authorize_action(false)
33
+ end
34
+
35
+ def create?
36
+ authorize_action(false)
37
+ end
38
+
39
+ def update?
40
+ authorize_action(false)
41
+ end
42
+
43
+ def destroy?
44
+ authorize_action(false)
45
+ end
46
+
47
+ def permitted_attributes_for_create
48
+ record.create_params
49
+ end
50
+
51
+ def permitted_attributes_for_show
52
+ record.show_params
53
+ end
54
+
55
+ def permitted_attributes_for_update
56
+ record.update_params
57
+ end
58
+
59
+ class Scope
60
+ attr_reader :auth_owner, :scope
61
+
62
+ def initialize(auth_owner, scope)
63
+ @auth_owner = auth_owner
64
+ @scope = scope
65
+ end
66
+
67
+ def resolve
68
+ scope.none
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base_policy"
4
+
5
+ module Rhino
6
+ # CrudPolicy finds the role for the auth owner and then uses that role
7
+ # to look up a corresponding policy.
8
+ #
9
+ # Authorization for an action, scoping and permitted params are then
10
+ # delegated to that policy
11
+ class CrudPolicy < ::Rhino::BasePolicy
12
+ def check_action(action)
13
+ # If any role allows the action, return true
14
+ # There should only be multiple roles in the case of index because we
15
+ # can't trace to a specific owner for the ActiveRecord class
16
+ # FIXME: Make sure this is ok for create - ie the ownership is enforced/checked
17
+ Rhino.base_owner.roles_for_auth(auth_owner, record).each do |role, _base_owner_array|
18
+ policy_class = Rhino::PolicyHelper.find_policy(role, record)
19
+ next unless policy_class
20
+
21
+ return true if policy_class.new(auth_owner, record).send(action)
22
+ end
23
+
24
+ false
25
+ end
26
+
27
+ def permitted_attributes(action)
28
+ # There should only be one match because record should be a instance not a class
29
+ # for show/create/update
30
+ Rhino.base_owner.roles_for_auth(auth_owner, record).each do |role, _base_owner_array|
31
+ policy_class = Rhino::PolicyHelper.find_policy(role, record)
32
+
33
+ return policy_class.new(auth_owner, record).send("permitted_attributes_for_#{action}") if policy_class
34
+ end
35
+
36
+ # Return nothing if we didn't find a policy
37
+ []
38
+ end
39
+
40
+ def index?
41
+ authorize_action(check_action(:index?))
42
+ end
43
+
44
+ def show?
45
+ authorize_action(check_action(:show?))
46
+ end
47
+
48
+ def create?
49
+ authorize_action(check_action(:create?))
50
+ end
51
+
52
+ def update?
53
+ authorize_action(check_action(:update?))
54
+ end
55
+
56
+ def destroy?
57
+ authorize_action(check_action(:destroy?))
58
+ end
59
+
60
+ def permitted_attributes_for_create
61
+ permitted_attributes(:create)
62
+ end
63
+
64
+ def permitted_attributes_for_show
65
+ permitted_attributes(:show)
66
+ end
67
+
68
+ def permitted_attributes_for_update
69
+ permitted_attributes(:update)
70
+ end
71
+
72
+ class Scope < ::Rhino::BasePolicy::Scope
73
+ # rubocop:todo Metrics/MethodLength
74
+ def resolve # rubocop:disable Metrics/AbcSize,
75
+ role_scopes = []
76
+
77
+ # Get every role for the auth owner
78
+ Rhino.base_owner.roles_for_auth(auth_owner).each do |role, base_owner_array|
79
+ base_owner_array.each do |base_owner|
80
+ scope_class = Rhino::PolicyHelper.find_policy_scope(role, scope)
81
+ next unless scope_class
82
+
83
+ # Collect all the role based scopes
84
+ # Use the scope for this role and join/select the base owner
85
+ scope_instance = scope_class.new(auth_owner, scope)
86
+ # NUB-367 and NUB-392
87
+ # default scopes with includes and order can cause problems
88
+ scope_instance = scope_instance.resolve.unscope(:includes, :order)
89
+ role_scopes << scope_instance.select(tnpk(scope)).joins(scope.joins_for_base_owner).where(tnpk(Rhino.base_owner) => base_owner.id)
90
+ end
91
+ end
92
+
93
+ # Select with present? because scope.none with produce empty sql string
94
+ role_scopes = role_scopes.map(&:to_sql).compact_blank
95
+ return scope.none unless role_scopes.present?
96
+
97
+ # UNION all the role based scopes
98
+ # The front end needs to filter per base owner as appropriate
99
+ scope.where("#{tnpk(scope)} in (#{role_scopes.join(' UNION ')})")
100
+ end
101
+ # rubocop:enable Metrics/MethodLength
102
+
103
+ private
104
+ def tnpk(scope)
105
+ "#{scope.table_name}.#{scope.primary_key}"
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rhino
4
+ class EditorPolicy < ::Rhino::ViewerPolicy
5
+ def update?
6
+ authorize_action(true)
7
+ end
8
+
9
+ class Scope < ::Rhino::ViewerPolicy::Scope
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rhino
4
+ class GlobalPolicy < ::Rhino::ViewerPolicy
5
+ class Scope < ::Rhino::ViewerPolicy::Scope
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rhino
4
+ class ResourceInfoPolicy < ::Rhino::BasePolicy
5
+ def index?
6
+ authorize_action(true)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rhino
4
+ class UserPolicy < ::Rhino::ViewerPolicy
5
+ class Scope < ::Rhino::ViewerPolicy::Scope
6
+ # We allow other users in the org to view the user
7
+ def resolve # rubocop:disable Metrics/AbcSize
8
+ return scope.none unless auth_owner
9
+
10
+ base_owner_pk = "#{Rhino.base_owner.table_name}.#{Rhino.base_owner.primary_key}"
11
+
12
+ # Base owners for the user
13
+ base_owners = scope.joins(scope.joins_for_base_owner).where(id: auth_owner.id).pluck(base_owner_pk)
14
+
15
+ # Users related to the base owners
16
+ scope.joins(scope.joins_for_base_owner).where(base_owner_pk => base_owners).distinct
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rhino
4
+ class ViewerPolicy < ::Rhino::BasePolicy
5
+ def index?
6
+ authorize_action(true)
7
+ end
8
+
9
+ def show?
10
+ authorize_action(true)
11
+ end
12
+
13
+ class Scope < ::Rhino::BasePolicy::Scope
14
+ def resolve
15
+ scope.all
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rgl/implicit"
4
+ require "rgl/dot"
5
+
6
+ module Rhino
7
+ class InfoGraph
8
+ include Rhino::Resource
9
+
10
+ rhino_owner_global
11
+
12
+ rhino_routing only: [:index], path: "info/graph"
13
+ rhino_controller :simple_stream
14
+ rhino_policy :resource_info
15
+
16
+ def self.describe
17
+ nil
18
+ end
19
+
20
+ FILENAME = "rhino-resource-graph"
21
+ FILETYPE = "png"
22
+
23
+ def self.build_graph
24
+ RGL::ImplicitGraph.new do |g|
25
+ # Add every rhino resource
26
+ g.vertex_iterator { |c| Rhino.resource_classes.each(&c) }
27
+
28
+ # If its owned by another resoource, link it
29
+ g.adjacent_iterator { |v, c| c.call(v.resource_owned_by.to_s.camelize.constantize) if v&.resource_owned_by && !v.global_owner? }
30
+
31
+ g.directed = true
32
+ end
33
+ end
34
+
35
+ def self.index
36
+ build_graph.write_to_graphic_file(FILETYPE, FILENAME)
37
+
38
+ { file: [FILENAME, FILETYPE].join("."), type: "image/png", disposition: "inline" }
39
+ end
40
+ end
41
+ end