rhino_project_core 0.20.0.alpha.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.
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
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 0f2e6d0cf9a761ebe9b75b3cacf2b6345a2b91df4d9d3f456a9108492aac0988
4
+ data.tar.gz: 45365e2f7d1efe25bbfc153a497804758a43bc160c2d13a22918af94390d0790
5
+ SHA512:
6
+ metadata.gz: bdb873a1c1e4717d74dc52dda547b573a921e730023fa6ea307a2df0b776fd579832aba12da869d1c33e2edc2d2a39f7a5bc33a501e177ccb7cf0db71c7d6908
7
+ data.tar.gz: 7375ef91e536a7a77b1a39e85ee5c501b035b6bd4127ad824064424ef78ae64b6114600dd88c6eade02ce7350fa1a3ffe5787a80ac07db4e625cf823c90c5444
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2020-present Codalio Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,28 @@
1
+ # Rhino
2
+ Short description and motivation.
3
+
4
+ ## Usage
5
+ How to use my plugin.
6
+
7
+ ## Installation
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'rhino'
12
+ ```
13
+
14
+ And then execute:
15
+ ```bash
16
+ $ bundle
17
+ ```
18
+
19
+ Or install it yourself as:
20
+ ```bash
21
+ $ gem install rhino
22
+ ```
23
+
24
+ ## Contributing
25
+ Contribution directions go here.
26
+
27
+ ## License
28
+ 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,35 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ task :package
10
+
11
+ RDoc::Task.new(:rdoc) do |rdoc|
12
+ rdoc.rdoc_dir = 'rdoc'
13
+ rdoc.title = 'Rhino'
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("test/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 'rake/testtask'
27
+
28
+ Rake::TestTask.new do |t|
29
+ t.libs << "test"
30
+ t.test_files = FileList["test/**/*_test.rb"].exclude("test/system/**/*", "test/dummy/**/*")
31
+ t.verbose = true
32
+ t.warning = false
33
+ end
34
+
35
+ task default: :test
Binary file
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rhino
4
+ module Authenticated
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ prepend_before_action :authenticate_user!
9
+ end
10
+
11
+ # Overrides the default devise_token_auth handler
12
+ def render_authenticate_error
13
+ cookies.delete(DeviseTokenAuth.cookie_name, domain: DeviseTokenAuth.cookie_attributes[:domain])
14
+
15
+ super
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_record/associations"
4
+
5
+ module Rhino
6
+ module ErrorHandling
7
+ extend ActiveSupport::Concern
8
+
9
+ included do # rubocop:disable Metrics/BlockLength
10
+ rescue_from Exception, with: :handle_uncaught_error
11
+
12
+ # ActiveRecord::DeleteRestrictionError is for dependent: :restrict_with_exception
13
+ rescue_from ActionController::ParameterMissing, ActiveRecord::DeleteRestrictionError do |e|
14
+ render json: { errors: [e.message] }, status: :bad_request
15
+ end
16
+
17
+ rescue_from Pundit::NotAuthorizedError, with: :forbidden
18
+
19
+ # ActiveRecord::RecordNotDestroyed is for dependent: :restrict_with_error
20
+ rescue_from ActiveRecord::RecordInvalid, ActiveRecord::RecordNotDestroyed do |e|
21
+ unprocessable e.record.errors
22
+ end
23
+
24
+ rescue_from ActiveRecord::RecordNotFound, with: :not_found
25
+
26
+ def handle_uncaught_error(exception)
27
+ # Send to rollbar if available
28
+ Rollbar.error(exception) if defined? Rollbar
29
+
30
+ logger.error("Internal server error#{exception.class} #{exception.message} #{exception.backtrace.join("\n")}")
31
+
32
+ render json: { errors: ['Internal server error.'] },
33
+ status: :internal_server_error
34
+ end
35
+
36
+ def not_found
37
+ render json: { errors: ['Not found.'] }, status: :not_found
38
+ end
39
+
40
+ def bad_request(errors = nil)
41
+ render json: { errors: (errors || ['Bad request.']) },
42
+ status: :bad_request
43
+ end
44
+
45
+ def forbidden
46
+ render json: { errors: ['Access denied.'] }, status: :forbidden
47
+ end
48
+
49
+ def unprocessable(errors = nil)
50
+ render json: {
51
+ errors: (errors&.to_hash(full_messages: true) || ['Unprocessable request.'])
52
+ }, status: :unprocessable_entity
53
+ end
54
+
55
+ def cors
56
+ render json: {}
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rhino
4
+ module PaperTrailWhodunnit
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ before_action :set_paper_trail_whodunnit if defined? PaperTrail
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rhino
4
+ module Permit
5
+ extend ActiveSupport::Concern
6
+
7
+ protected
8
+ # The params are wrapped with 'crud' if the crud_controller is called directly
9
+ # instead of via a customization class
10
+ #
11
+ # Protected to prevent polluting the action method
12
+ #
13
+ # FIXME: Couldn't find a way to call wrap_parameters appropriately
14
+ # FIXME: Will some sort of namespacing break this?
15
+ # _wrapper_options is semi-private but we can get at it
16
+ def pundit_params_for(_record)
17
+ params.require(_wrapper_options.name)
18
+ end
19
+
20
+ private
21
+ def permit_and_transform(model = @model)
22
+ klass.transform_params(permitted_attributes(model))
23
+ end
24
+
25
+ def permit_model(model = @model)
26
+ model_policy = Pundit.policy(current_user, model)
27
+
28
+ model_params = ActionController::Parameters.new(model.to_caching_json)
29
+ model_params[:can_current_user_edit] = model_policy.update?
30
+ model_params[:can_current_user_destroy] = model_policy.destroy?
31
+ model_params.permit(model_policy.permitted_attributes_for_show + %i[can_current_user_edit can_current_user_destroy])
32
+ end
33
+
34
+ def permit_and_render
35
+ render json: permit_model
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rhino
4
+ module SetCurrentUser
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ before_action do
9
+ Current.user = current_user
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rhino
4
+ class AccountController < BaseController
5
+ include Rhino::Authenticated
6
+ include Rhino::Permit
7
+
8
+ # Confirm we are calling authorize and scope correctly
9
+ after_action :verify_authorized
10
+ after_action :verify_policy_scoped
11
+
12
+ def show
13
+ @model = authorize_resource
14
+
15
+ permit_and_render
16
+ end
17
+
18
+ def update
19
+ @model = authorize_resource
20
+ @model.update!(permit_and_transform)
21
+
22
+ permit_and_render
23
+ end
24
+
25
+ private
26
+ def find_resource
27
+ policy_scope(klass).first
28
+ end
29
+
30
+ def authorize_resource
31
+ authorize find_resource
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rhino
4
+ class ActiveModelExtensionController < BaseController
5
+ include Rhino::Authenticated
6
+ include Rhino::Permit
7
+
8
+ # Confirm we are calling authorize and scope correctly
9
+ after_action :verify_authorized
10
+ # after_action :verify_policy_scoped, only: %i[index show]
11
+
12
+ def create
13
+ @model = authorize klass.new(permit_and_transform(klass.new))
14
+ klass.backing_store_create(@model)
15
+
16
+ permit_and_render
17
+ end
18
+
19
+ def index
20
+ authorize klass
21
+ @models = klass.backing_store_index
22
+
23
+ # FIXME: - policy and sieve scopings
24
+ # @models = klass.sieves.resolve(policy_scope(klass), params)
25
+ render json: {
26
+ results: @models.map { |m| permit_model(m) },
27
+ total: @models.count
28
+ }
29
+ end
30
+
31
+ def show
32
+ @model = authorize(klass.backing_store_show(params[:id]))
33
+
34
+ permit_and_render
35
+ end
36
+
37
+ def update
38
+ @model = authorize klass.new(permit_and_transform(klass.new))
39
+ # FIXME: Return updated model
40
+ @model.backing_store_update
41
+
42
+ permit_and_render
43
+ end
44
+
45
+ def destroy
46
+ @model = authorize klass.backing_store_show(params[:id])
47
+ @model.backing_store_destroy
48
+
49
+ permit_and_render
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rhino
4
+ class BaseController < ActionController::API
5
+ include ActionController::Cookies
6
+ include DeviseTokenAuth::Concerns::SetUserByToken
7
+ include Pundit
8
+
9
+ include Rhino::ErrorHandling
10
+ include Rhino::SetCurrentUser
11
+ include Rhino::PaperTrailWhodunnit
12
+
13
+ # https://api.rubyonrails.org/classes/AbstractController/Base.html#method-c-abstract-21
14
+ # Prevents the utility methods below from showing up as actions in CrudController
15
+ abstract!
16
+
17
+ respond_to :json
18
+
19
+ def klass
20
+ @klass ||= params.delete(:rhino_resource).constantize
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rhino
4
+ class CrudController < BaseController
5
+ include Rhino::Authenticated
6
+ include Rhino::Permit
7
+
8
+ # Confirm we are calling authorize and scope correctly
9
+ after_action :verify_authorized
10
+ after_action :verify_policy_scoped, only: %i[index show]
11
+
12
+ wrap_parameters :crud, format: [:json]
13
+
14
+ def create
15
+ @model = authorize klass.new(permit_and_transform(klass))
16
+ @model.save!
17
+
18
+ permit_and_render
19
+ end
20
+
21
+ def index
22
+ authorize klass
23
+
24
+ @models = klass.sieves.resolve(policy_scope(klass), params)
25
+ render json: {
26
+ results: @models.eager_load_refs.map { |m| permit_model(m) },
27
+ total: @models.unscope(:limit, :offset).reselect(:id).count
28
+ }
29
+ end
30
+
31
+ def show
32
+ @model = authorize find_resource(policy_scope(klass).eager_load_refs)
33
+
34
+ permit_and_render
35
+ end
36
+
37
+ def update
38
+ @model = authorize find_resource
39
+ @model.update!(permit_and_transform)
40
+
41
+ permit_and_render
42
+ end
43
+
44
+ def destroy
45
+ @model = authorize find_resource
46
+ @model.destroy!
47
+
48
+ permit_and_render
49
+ end
50
+
51
+ private
52
+ def find_resource(scope = klass.all)
53
+ scope = scope.friendly if scope.respond_to? :friendly
54
+ scope.find(params[:id])
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rhino
4
+ class SimpleController < BaseController
5
+ def action_missing(action)
6
+ authorize klass, "#{action}?".to_sym
7
+
8
+ method = klass.method(action)
9
+
10
+ render json: method.parameters.any? ? klass.send(action, params) : klass.send(action)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rhino
4
+ class SimpleStreamController < BaseController
5
+ def action_missing(action)
6
+ authorize klass, "#{action}?".to_sym
7
+
8
+ info = klass.send(action)
9
+ send_file(info[:file], info.except(:file)) if info.key?(:file)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rhino
4
+ module OmniauthHelper
5
+ module_function
6
+
7
+ def strategies_metadata
8
+ params = { resource_class: "User" }
9
+
10
+ strategies.each_with_object([]) do |strategy, array|
11
+ array << {
12
+ name: strategy,
13
+ path: "#{::OmniAuth.config.path_prefix}/#{strategy}?#{params.to_param}"
14
+ }
15
+ end
16
+ end
17
+
18
+ def strategies
19
+ strategies = ENV.keys.filter_map do |env|
20
+ match = /AUTH_(.*)_CLIENT_ID/.match(env)
21
+ next unless match
22
+
23
+ match[1].downcase.to_sym
24
+ end.uniq
25
+
26
+ strategies += [:developer] if Rails.env.development? && !Rake.try(:application)
27
+
28
+ strategies
29
+ end
30
+
31
+ def app_info(strategy)
32
+ case strategy
33
+ when :developer
34
+ []
35
+ when :azure_oauth2
36
+ azure_info
37
+ when :auth0
38
+ auth0_info
39
+ else
40
+ env_keys(strategy)
41
+ end
42
+ end
43
+
44
+ def env_keys(strategy)
45
+ ups = strategy.to_s.upcase
46
+ [ENV["AUTH_#{ups}_CLIENT_ID"], ENV["AUTH_#{ups}_SECRET_KEY"]]
47
+ end
48
+
49
+ def azure_info
50
+ [
51
+ client_id: ENV["AUTH_AZURE_OAUTH2_CLIENT_ID"],
52
+ client_secret: ENV["AUTH_AZURE_OAUTH2_SECRET_KEY"],
53
+ tenant_id: ENV["AUTH_AZURE_OAUTH2_TENANT_ID"]
54
+ ]
55
+ end
56
+
57
+ def auth0_info
58
+ [client_id: ENV["AUTH_AUTH0_CLIENT_ID"],
59
+ client_secret: ENV["AUTH_AUTH0_SECRET_KEY"],
60
+ domain: ENV["AUTH_AUTH0_DOMAIN"],
61
+ callback_path: "/api/auth/omniauth/auth0/callback",
62
+ authorize_params: {
63
+ scope: "openid profile"
64
+ }]
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rhino
4
+ module PolicyHelper
5
+ module_function
6
+
7
+ # Looks for the policy associated with a role and resource
8
+ #
9
+ # If a policy for a role and resource is not found, looks for the policy
10
+ # associated with the role.
11
+ #
12
+ # === Examples
13
+ #
14
+ # find_policy(:author, Blog)
15
+ #
16
+ def find_policy(role, resource, additional_class = nil)
17
+ role = role.to_s if role.is_a? Symbol
18
+ role = role.classify
19
+
20
+ resource = resource.class if resource.class != Class
21
+ resource = resource.to_s.classify
22
+
23
+ policy_class = 'Policy'
24
+ policy_class = "#{policy_class}::#{additional_class}" if additional_class
25
+
26
+ # Look for role and resource specific policy
27
+ policy_constant = "#{role}#{resource}#{policy_class}".safe_constantize
28
+ return policy_constant if policy_constant.present?
29
+
30
+ # Fall back to just the role specific policy
31
+ policy_constant = "#{role}#{policy_class}".safe_constantize
32
+ return policy_constant if policy_constant.present?
33
+
34
+ # Fall back just to the rhino version
35
+ "Rhino::#{role}#{policy_class}".safe_constantize
36
+ end
37
+
38
+ def find_policy_scope(role, resource)
39
+ find_policy(role, resource, 'Scope')
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rhino
4
+ module SegmentHelper
5
+ module_function
6
+
7
+ def track(type, user)
8
+ segment_track(type, user)
9
+ rescue StandardError => e
10
+ Rollbar.error(e)
11
+ end
12
+
13
+ def track_account(type, organization, users_role = nil)
14
+ segment_track_account(type, organization, users_role)
15
+ rescue StandardError => e
16
+ Rollbar.error(e)
17
+ end
18
+
19
+ def track_invite(users_role_invite)
20
+ segment_track_invite(users_role_invite)
21
+ rescue StandardError => e
22
+ Rollbar.error(e)
23
+ end
24
+
25
+ def segment_track(type, user)
26
+ Analytics.track(
27
+ user_id: user.id,
28
+ event: type,
29
+ properties: {
30
+ name: user.name,
31
+ email: user.email,
32
+ current_sign_in_ip: user.current_sign_in_ip,
33
+ last_sign_in_ip: user.last_sign_in_ip,
34
+ approved: user.approved
35
+ }
36
+ )
37
+ end
38
+
39
+ def segment_track_account(type, organization, users_role)
40
+ properties = {}
41
+ properties[:account_name] = organization.name
42
+ properties[:user_email] = users_role.user&.email unless users_role.nil?
43
+ properties[:role] = users_role.role&.name unless users_role.nil?
44
+ Analytics.track(
45
+ user_id: users_role.nil? ? organization.id : users_role.user&.id,
46
+ event: type,
47
+ properties:
48
+ )
49
+ end
50
+
51
+ def segment_track_invite(users_role_invite)
52
+ Analytics.track(
53
+ event: "Invite Sent",
54
+ user_id: Rhino::Current.user&.id,
55
+ properties: {
56
+ invitee_email: users_role_invite.email,
57
+ invitee_role: users_role_invite.role&.name
58
+ }
59
+ )
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rhino
4
+ class Account < User
5
+ self.table_name = "users"
6
+
7
+ rhino_owner_global
8
+
9
+ rhino_routing only: %i[show update], singular: true
10
+ rhino_controller :account
11
+ rhino_policy :account
12
+ end
13
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rhino
4
+ class Current < ActiveSupport::CurrentAttributes
5
+ attribute :user
6
+ end
7
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rhino
4
+ class User < ApplicationRecord
5
+ self.abstract_class = true
6
+
7
+ include DeviseTokenAuth::Concerns::User
8
+
9
+ rhino_properties_read only: %i[id name nickname email image]
10
+ rhino_properties_create only: %i[name nickname email]
11
+ rhino_properties_update only: %i[name nickname]
12
+
13
+ rhino_policy :user
14
+
15
+ def self.devise_modules_to_load
16
+ modules = %i[database_authenticatable registerable recoverable rememberable trackable validatable confirmable omniauthable]
17
+ modules.push :invitable if Rhino.resources.include?("Organization")
18
+ end
19
+ devise(*devise_modules_to_load)
20
+
21
+ validates :email, uniqueness: { case_sensitive: false }
22
+ after_create_commit :track_sign_up
23
+
24
+ def display_name
25
+ name || email
26
+ end
27
+
28
+ def self.roles_for_auth(auth_owner, record = nil)
29
+ return {} unless auth_owner
30
+
31
+ # If user is logged in, but no record, they are still an admin for their data
32
+ # Otherwise owner must match to be an admin
33
+ # A list of roles as hash keys with an array of base_owners for each
34
+ return { admin: [auth_owner] } if !record.respond_to?(:base_owner_ids) || record.base_owner_ids.include?(auth_owner&.id)
35
+
36
+ {}
37
+ end
38
+
39
+ private
40
+ def track_sign_up
41
+ Rhino::SegmentHelper.track("Signed Up", self)
42
+ end
43
+ end
44
+ end