ibrain-core 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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +75 -0
- data/Rakefile +7 -0
- data/app/controllers/concerns/ibrain_errors.rb +23 -0
- data/app/controllers/concerns/ibrain_handler.rb +42 -0
- data/app/controllers/ibrain/base_controller.rb +28 -0
- data/app/controllers/ibrain/graphql_controller.rb +55 -0
- data/app/graphql/ibrain/base_schema.rb +52 -0
- data/app/graphql/ibrain/extentions/default_value.rb +15 -0
- data/app/graphql/ibrain/interfaces/base_interface.rb +5 -0
- data/app/graphql/ibrain/interfaces/person_interface.rb +15 -0
- data/app/graphql/ibrain/interfaces/record_interface.rb +10 -0
- data/app/graphql/ibrain/lazy/base.rb +8 -0
- data/app/graphql/ibrain/loaders/association_loader.rb +61 -0
- data/app/graphql/ibrain/mutations/base_mutation.rb +35 -0
- data/app/graphql/ibrain/policies/base_policy.rb +45 -0
- data/app/graphql/ibrain/policies/graphql_policy.rb +8 -0
- data/app/graphql/ibrain/resolvers/base_aggregate.rb +9 -0
- data/app/graphql/ibrain/resolvers/base_resolver.rb +15 -0
- data/app/graphql/ibrain/types/aggregate_type.rb +9 -0
- data/app/graphql/ibrain/types/base_argument.rb +11 -0
- data/app/graphql/ibrain/types/base_connection.rb +16 -0
- data/app/graphql/ibrain/types/base_edge.rb +10 -0
- data/app/graphql/ibrain/types/base_enum.rb +8 -0
- data/app/graphql/ibrain/types/base_field.rb +15 -0
- data/app/graphql/ibrain/types/base_input_object.rb +9 -0
- data/app/graphql/ibrain/types/base_interface.rb +14 -0
- data/app/graphql/ibrain/types/base_node.rb +13 -0
- data/app/graphql/ibrain/types/base_object.rb +14 -0
- data/app/graphql/ibrain/types/base_query_type.rb +14 -0
- data/app/graphql/ibrain/types/base_scalar.rb +8 -0
- data/app/graphql/ibrain/types/base_union.rb +10 -0
- data/app/graphql/ibrain/types/filter_type.rb +8 -0
- data/app/graphql/ibrain/types/node_type.rb +11 -0
- data/app/graphql/ibrain/util/field_combiner.rb +13 -0
- data/app/graphql/ibrain/util/query_combiner.rb +13 -0
- data/app/graphql/mutations/insert_user.rb +18 -0
- data/app/models/ibrain/ability.rb +51 -0
- data/app/models/ibrain/application_record.rb +7 -0
- data/app/models/ibrain/base.rb +47 -0
- data/app/models/ibrain/concerns/ransackable_attributes.rb +22 -0
- data/app/models/ibrain/concerns/soft_deletable.rb +16 -0
- data/app/models/ibrain/concerns/user_api_authentication.rb +23 -0
- data/app/models/ibrain/concerns/user_methods.rb +25 -0
- data/app/models/ibrain/legacy_user.rb +19 -0
- data/app/models/ibrain/role.rb +14 -0
- data/app/models/ibrain/role_user.rb +18 -0
- data/config/initializers/friendly_id.rb +87 -0
- data/config/locales/en.yml +10 -0
- data/config/locales/jp.yml +10 -0
- data/config/locales/vi.yml +10 -0
- data/config/routes.rb +9 -0
- data/lib/generators/ibrain/graphql/core.rb +75 -0
- data/lib/generators/ibrain/graphql/mutation_generator.rb +58 -0
- data/lib/generators/ibrain/graphql/object_generator.rb +80 -0
- data/lib/generators/ibrain/graphql/resolver_generator.rb +33 -0
- data/lib/generators/ibrain/graphql/resolvers_generator.rb +59 -0
- data/lib/generators/ibrain/graphql/templates/aggregate.erb +10 -0
- data/lib/generators/ibrain/graphql/templates/mutation.erb +16 -0
- data/lib/generators/ibrain/graphql/templates/object.erb +11 -0
- data/lib/generators/ibrain/graphql/templates/resolver.erb +15 -0
- data/lib/generators/ibrain/graphql/templates/resolvers.erb +13 -0
- data/lib/generators/ibrain/graphql/type_generator.rb +101 -0
- data/lib/generators/ibrain/install/install_generator.rb +189 -0
- data/lib/generators/ibrain/install/templates/config/database.tt +23 -0
- data/lib/generators/ibrain/install/templates/config/initializers/cors.tt +25 -0
- data/lib/generators/ibrain/install/templates/config/initializers/ibrain.rb.tt +55 -0
- data/lib/generators/ibrain/install/templates/config/puma.tt +43 -0
- data/lib/generators/ibrain/install/templates/graphql/app_schema.rb.tt +4 -0
- data/lib/generators/ibrain/install/templates/graphql/types/mutation_type.rb.tt +10 -0
- data/lib/generators/ibrain/install/templates/graphql/types/query_type.rb.tt +13 -0
- data/lib/ibrain/app_configuration.rb +66 -0
- data/lib/ibrain/config.rb +5 -0
- data/lib/ibrain/core/class_constantizer.rb +41 -0
- data/lib/ibrain/core/controller_helpers/auth.rb +64 -0
- data/lib/ibrain/core/controller_helpers/current_host.rb +17 -0
- data/lib/ibrain/core/controller_helpers/response.rb +52 -0
- data/lib/ibrain/core/controller_helpers/strong_parameters.rb +21 -0
- data/lib/ibrain/core/engine.rb +16 -0
- data/lib/ibrain/core/environment.rb +17 -0
- data/lib/ibrain/core/environment_extension.rb +27 -0
- data/lib/ibrain/core/role_configuration.rb +72 -0
- data/lib/ibrain/core/validators/email.rb +23 -0
- data/lib/ibrain/core/version.rb +17 -0
- data/lib/ibrain/core/versioned_value.rb +73 -0
- data/lib/ibrain/core.rb +86 -0
- data/lib/ibrain/encryptor.rb +27 -0
- data/lib/ibrain/i18n.rb +17 -0
- data/lib/ibrain/logger.rb +23 -0
- data/lib/ibrain/permission_sets/base.rb +33 -0
- data/lib/ibrain/permission_sets/super_user.rb +11 -0
- data/lib/ibrain/permission_sets.rb +4 -0
- data/lib/ibrain/permitted_attributes.rb +26 -0
- data/lib/ibrain/preferences/configuration.rb +170 -0
- data/lib/ibrain/preferences/preferable.rb +183 -0
- data/lib/ibrain/preferences/preferable_class_methods.rb +140 -0
- data/lib/ibrain/user_class_handle.rb +29 -0
- data/lib/ibrain_core.rb +3 -0
- data/lib/tasks/ibrain/auto_annotate_models.rake +61 -0
- data/lib/tasks/ibrain/core_tasks.rake +5 -0
- data/lib/tasks/ibrain/ridgepole.rake +37 -0
- metadata +293 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Puma can serve each request in a thread from an internal thread pool.
|
|
2
|
+
# The `threads` method setting takes two numbers: a minimum and maximum.
|
|
3
|
+
# Any libraries that use thread pools should be configured to match
|
|
4
|
+
# the maximum value specified for Puma. Default is set to 5 threads for minimum
|
|
5
|
+
# and maximum; this matches the default thread size of Active Record.
|
|
6
|
+
#
|
|
7
|
+
max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
|
|
8
|
+
min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count }
|
|
9
|
+
threads min_threads_count, max_threads_count
|
|
10
|
+
|
|
11
|
+
# Specifies the `worker_timeout` threshold that Puma will use to wait before
|
|
12
|
+
# terminating a worker in development environments.
|
|
13
|
+
#
|
|
14
|
+
worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development"
|
|
15
|
+
|
|
16
|
+
# Specifies the `port` that Puma will listen on to receive requests; default is 3000.
|
|
17
|
+
#
|
|
18
|
+
port ENV.fetch("PORT") { 3000 }
|
|
19
|
+
|
|
20
|
+
# Specifies the `environment` that Puma will run in.
|
|
21
|
+
#
|
|
22
|
+
environment ENV.fetch("RAILS_ENV") { "development" }
|
|
23
|
+
|
|
24
|
+
# Specifies the `pidfile` that Puma will use.
|
|
25
|
+
pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }
|
|
26
|
+
|
|
27
|
+
# Specifies the number of `workers` to boot in clustered mode.
|
|
28
|
+
# Workers are forked web server processes. If using threads and workers together
|
|
29
|
+
# the concurrency of the application would be max `threads` * `workers`.
|
|
30
|
+
# Workers do not work on JRuby or Windows (both of which do not support
|
|
31
|
+
# processes).
|
|
32
|
+
#
|
|
33
|
+
# workers ENV.fetch("WEB_CONCURRENCY") { 2 }
|
|
34
|
+
|
|
35
|
+
# Use the `preload_app!` method when specifying a `workers` number.
|
|
36
|
+
# This directive tells Puma to first boot the application and load code
|
|
37
|
+
# before forking the application. This takes advantage of Copy On Write
|
|
38
|
+
# process behavior so workers use less memory.
|
|
39
|
+
#
|
|
40
|
+
# preload_app!
|
|
41
|
+
|
|
42
|
+
# Allow puma to be restarted by `rails restart` command.
|
|
43
|
+
plugin :tmp_restart
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module Types
|
|
2
|
+
class QueryType < Ibrain::Types::BaseObject
|
|
3
|
+
# Add `node(id: ID!) and `nodes(ids: [ID!]!)`
|
|
4
|
+
include GraphQL::Types::Relay::HasNodeField
|
|
5
|
+
include GraphQL::Types::Relay::HasNodesField
|
|
6
|
+
|
|
7
|
+
# Add root-level fields here.
|
|
8
|
+
# They will be entry points for queries on your schema.
|
|
9
|
+
|
|
10
|
+
# Example with user resolvers
|
|
11
|
+
# field :users, resolver: Resolvers::UsersResolver
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This is the primary location for defining ibrain preferences
|
|
4
|
+
#
|
|
5
|
+
# The expectation is that this is created once and stored in
|
|
6
|
+
# the ibrain environment
|
|
7
|
+
#
|
|
8
|
+
# setters:
|
|
9
|
+
# a.color = :blue
|
|
10
|
+
# a[:color] = :blue
|
|
11
|
+
# a.set :color = :blue
|
|
12
|
+
# a.preferred_color = :blue
|
|
13
|
+
#
|
|
14
|
+
# getters:
|
|
15
|
+
# a.color
|
|
16
|
+
# a[:color]
|
|
17
|
+
# a.get :color
|
|
18
|
+
# a.preferred_color
|
|
19
|
+
#
|
|
20
|
+
require 'ibrain/preferences/configuration'
|
|
21
|
+
require 'ibrain/core/environment'
|
|
22
|
+
|
|
23
|
+
module Ibrain
|
|
24
|
+
class AppConfiguration < Preferences::Configuration
|
|
25
|
+
# Preferences (alphabetized to more easily lookup particular preferences)
|
|
26
|
+
|
|
27
|
+
# @!attribute [rw] guest_token_cookie_options
|
|
28
|
+
# @return [Hash] Add additional guest_token cookie options here (ie. domain or path)
|
|
29
|
+
preference :guest_token_cookie_options, :hash, default: {}
|
|
30
|
+
|
|
31
|
+
# @!attribute [rw] generate_api_key_for_all_roles
|
|
32
|
+
# @return [Boolean] Allow generating api key automatically for user
|
|
33
|
+
# at role_user creation for all roles. (default: +false+)
|
|
34
|
+
preference :generate_api_key_for_all_roles, :boolean, default: false
|
|
35
|
+
|
|
36
|
+
# @!attribute [rw] mails_from
|
|
37
|
+
# @return [String] Email address used as +From:+ field in transactional emails.
|
|
38
|
+
preference :mails_from, :string, default: 'ibrain@example.com'
|
|
39
|
+
|
|
40
|
+
preference :graphql_policy, :string, default: 'Ibrain::Policies::GraphqlPolicy'
|
|
41
|
+
|
|
42
|
+
# Api version for route config
|
|
43
|
+
preference :api_version, :string, default: 'v1'
|
|
44
|
+
|
|
45
|
+
# Graphql Schema name
|
|
46
|
+
preference :graphql_schema, :string, default: 'Ibrain::BaseSchema'
|
|
47
|
+
|
|
48
|
+
# Graphql Encryptor key
|
|
49
|
+
preference :ibrain_encryptor_key, :string, default: nil
|
|
50
|
+
|
|
51
|
+
def static_model_preferences
|
|
52
|
+
@static_model_preferences ||= Ibrain::Preferences::StaticModelPreferences.new
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def roles
|
|
56
|
+
@roles ||= Ibrain::RoleConfiguration.new.tap do |roles|
|
|
57
|
+
roles.assign_permissions :default, ['Ibrain::PermissionSets::DefaultCustomer']
|
|
58
|
+
roles.assign_permissions :admin, ['Ibrain::PermissionSets::SuperUser']
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def environment
|
|
63
|
+
@environment ||= Ibrain::Core::Environment.new(self)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'active_support/core_ext/module'
|
|
4
|
+
|
|
5
|
+
module Ibrain
|
|
6
|
+
module Core
|
|
7
|
+
module ClassConstantizer
|
|
8
|
+
class Set
|
|
9
|
+
include Enumerable
|
|
10
|
+
|
|
11
|
+
def initialize
|
|
12
|
+
@collection = ::Set.new
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def <<(klass)
|
|
16
|
+
@collection << klass.to_s
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def concat(klasses)
|
|
20
|
+
klasses.each do |klass|
|
|
21
|
+
self << klass
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
self
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
delegate :clear, :empty?, to: :@collection
|
|
28
|
+
|
|
29
|
+
def delete(object)
|
|
30
|
+
@collection.delete(object.to_s)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def each
|
|
34
|
+
@collection.each do |klass|
|
|
35
|
+
yield klass.constantize
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ibrain
|
|
4
|
+
module Core
|
|
5
|
+
module ControllerHelpers
|
|
6
|
+
module Auth
|
|
7
|
+
extend ActiveSupport::Concern
|
|
8
|
+
include Response
|
|
9
|
+
|
|
10
|
+
# @!attribute [rw] fallback_on_unauthorized
|
|
11
|
+
# @!scope class
|
|
12
|
+
# Extension point for overriding behaviour of access denied errors.
|
|
13
|
+
# Default behaviour is to redirect back or to "/unauthorized" with a flash
|
|
14
|
+
# message.
|
|
15
|
+
# @return [Proc] action to take when access denied error is raised.
|
|
16
|
+
|
|
17
|
+
included do
|
|
18
|
+
before_action :set_guest_token
|
|
19
|
+
helper_method :try_ibrain_current_user
|
|
20
|
+
|
|
21
|
+
class_attribute :fallback_on_unauthorized
|
|
22
|
+
self.fallback_on_unauthorized = -> do
|
|
23
|
+
error = ::Struct.new(
|
|
24
|
+
message: I18n.t('ibrain.authorization_failure')
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
render_json_error(error, :unauthorized)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
rescue_from CanCan::AccessDenied do
|
|
31
|
+
instance_exec(&fallback_on_unauthorized)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Needs to be overriden so that we use Brain's Ability rather than anyone else's.
|
|
36
|
+
def current_ability
|
|
37
|
+
@current_ability ||= Ibrain::Ability.new(try_ibrain_current_user)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def set_guest_token
|
|
41
|
+
# if cookies.signed[:guest_token].blank?
|
|
42
|
+
# cookies.permanent.signed[:guest_token] = Ibrain::Config[:guest_token_cookie_options].merge(
|
|
43
|
+
# value: SecureRandom.urlsafe_base64(nil, false),
|
|
44
|
+
# httponly: true
|
|
45
|
+
# )
|
|
46
|
+
# end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# proxy method to *possible* ibrain_current_user method
|
|
50
|
+
# Authentication extensions (such as ibrain-auth) are meant to provide ibrain_current_user
|
|
51
|
+
def try_ibrain_current_user
|
|
52
|
+
# This one will be defined by apps looking to hook into Ibrain
|
|
53
|
+
# As per authentication_helpers.rb
|
|
54
|
+
if respond_to?(:ibrain_current_user, true)
|
|
55
|
+
ibrain_current_user
|
|
56
|
+
# This one will be defined by Devise
|
|
57
|
+
elsif respond_to?(:current_ibrain_user, true)
|
|
58
|
+
current_ibrain_user
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ibrain
|
|
4
|
+
module Core
|
|
5
|
+
module ControllerHelpers
|
|
6
|
+
module CurrentHost
|
|
7
|
+
extend ActiveSupport::Concern
|
|
8
|
+
|
|
9
|
+
included do
|
|
10
|
+
before_action do
|
|
11
|
+
ActiveStorage::Current.host = request.base_url
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ibrain
|
|
4
|
+
module Core
|
|
5
|
+
module ControllerHelpers
|
|
6
|
+
module Response
|
|
7
|
+
extend ActiveSupport::Concern
|
|
8
|
+
|
|
9
|
+
included do
|
|
10
|
+
helper_method :render_json_error
|
|
11
|
+
helper_method :render_json_ok
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
protected
|
|
15
|
+
|
|
16
|
+
def render_json_error(error, status)
|
|
17
|
+
e_message = error.try(:record).try(:errors).try(:full_messages).try(:first)
|
|
18
|
+
e_message = error.try(:message) if e_message.blank?
|
|
19
|
+
|
|
20
|
+
backtrace = error.try(:backtrace).try(:join, "\n")
|
|
21
|
+
|
|
22
|
+
Ibrain::Logger.error e_message
|
|
23
|
+
Ibrain::Logger.error backtrace
|
|
24
|
+
|
|
25
|
+
render json: {
|
|
26
|
+
errors: [{
|
|
27
|
+
message: e_message,
|
|
28
|
+
extensions: {
|
|
29
|
+
code: status,
|
|
30
|
+
exception: {
|
|
31
|
+
stacktrace: [
|
|
32
|
+
backtrace
|
|
33
|
+
]
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}],
|
|
37
|
+
message: e_message,
|
|
38
|
+
data: nil
|
|
39
|
+
}, status: status
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def render_json_ok(data, message, errors = [])
|
|
43
|
+
render json: {
|
|
44
|
+
errors: errors,
|
|
45
|
+
message: message || I18n.t('ibrain.system.message.ok'),
|
|
46
|
+
data: data.as_json
|
|
47
|
+
}, status: :ok
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ibrain
|
|
4
|
+
module Core
|
|
5
|
+
module ControllerHelpers
|
|
6
|
+
module StrongParameters
|
|
7
|
+
def permitted_attributes
|
|
8
|
+
Ibrain::PermittedAttributes
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
delegate(*Ibrain::PermittedAttributes::ATTRIBUTES,
|
|
12
|
+
to: :permitted_attributes,
|
|
13
|
+
prefix: :permitted)
|
|
14
|
+
|
|
15
|
+
def permitted_user_attributes
|
|
16
|
+
permitted_attributes.user_attributes
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'ibrain/config'
|
|
4
|
+
|
|
5
|
+
module Ibrain
|
|
6
|
+
module Core
|
|
7
|
+
class Engine < ::Rails::Engine
|
|
8
|
+
isolate_namespace Ibrain
|
|
9
|
+
config.generators.api_only = true
|
|
10
|
+
|
|
11
|
+
initializer "ibrain.environment", before: :load_config_initializers do |app|
|
|
12
|
+
app.config.ibrain = Ibrain::Config.environment
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'ibrain/core/environment_extension'
|
|
4
|
+
|
|
5
|
+
module Ibrain
|
|
6
|
+
module Core
|
|
7
|
+
class Environment
|
|
8
|
+
include EnvironmentExtension
|
|
9
|
+
|
|
10
|
+
attr_accessor :preferences
|
|
11
|
+
|
|
12
|
+
def initialize(ibrain_config)
|
|
13
|
+
@preferences = ibrain_config
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'ibrain/core/class_constantizer'
|
|
4
|
+
|
|
5
|
+
module Ibrain
|
|
6
|
+
module Core
|
|
7
|
+
module EnvironmentExtension
|
|
8
|
+
extend ActiveSupport::Concern
|
|
9
|
+
|
|
10
|
+
class_methods do
|
|
11
|
+
def add_class_set(name)
|
|
12
|
+
define_method(name) do
|
|
13
|
+
set = instance_variable_get("@#{name}")
|
|
14
|
+
set ||= send("#{name}=", [])
|
|
15
|
+
set
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
define_method("#{name}=") do |klasses|
|
|
19
|
+
set = ClassConstantizer::Set.new
|
|
20
|
+
set.concat(klasses)
|
|
21
|
+
instance_variable_set("@#{name}", set)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'singleton'
|
|
4
|
+
require 'ibrain/core/class_constantizer'
|
|
5
|
+
|
|
6
|
+
module Ibrain
|
|
7
|
+
# A class responsible for associating {Ibrain::Role} with a list of permission sets.
|
|
8
|
+
#
|
|
9
|
+
# @see Ibrain::PermissionSets
|
|
10
|
+
#
|
|
11
|
+
# @example Adding order, data, and user display to customer service users.
|
|
12
|
+
# Ibrain::RoleConfiguration.configure do |config|
|
|
13
|
+
# config.assign_permissions :customer_service, [
|
|
14
|
+
# Ibrain::PermissionSets::UserDisplay,
|
|
15
|
+
# ]
|
|
16
|
+
# end
|
|
17
|
+
class RoleConfiguration
|
|
18
|
+
# An internal structure for the association between a role and a
|
|
19
|
+
# set of permissions.
|
|
20
|
+
class Role
|
|
21
|
+
attr_reader :name, :permission_sets
|
|
22
|
+
|
|
23
|
+
def initialize(name, permission_sets)
|
|
24
|
+
@name = name
|
|
25
|
+
@permission_sets = Ibrain::Core::ClassConstantizer::Set.new
|
|
26
|
+
@permission_sets.concat permission_sets
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
attr_accessor :roles
|
|
31
|
+
|
|
32
|
+
# Given a CanCan::Ability, and a user, determine what permissions sets can
|
|
33
|
+
# be activated on the ability, then activate them.
|
|
34
|
+
#
|
|
35
|
+
# This performs can/cannot declarations on the ability, and can modify its
|
|
36
|
+
# internal permissions.
|
|
37
|
+
#
|
|
38
|
+
# @param ability [CanCan::Ability] the ability to invoke declarations on
|
|
39
|
+
# @param user [#roles] the user that holds the roles association.
|
|
40
|
+
def activate_permissions!(ability, user)
|
|
41
|
+
ibrain_roles = ['default'] | user.roles.map(&:name)
|
|
42
|
+
applicable_permissions = Set.new
|
|
43
|
+
|
|
44
|
+
ibrain_roles.each do |role_name|
|
|
45
|
+
applicable_permissions |= roles[role_name].permission_sets
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
applicable_permissions.each do |permission_set|
|
|
49
|
+
permission_set.new(ability).activate!
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Not public due to the fact this class is a Singleton
|
|
54
|
+
# @!visibility private
|
|
55
|
+
def initialize
|
|
56
|
+
@roles = Hash.new do |hash, name|
|
|
57
|
+
hash[name] = Role.new(name, Set.new)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Assign permission sets for a {Ibrain::Role} that has the name of role_name
|
|
62
|
+
# @param role_name [Symbol, String] The name of the role to associate permissions with
|
|
63
|
+
# @param permission_sets [Array<Ibrain::PermissionSets::Base>, Set<Ibrain::PermissionSets::Base>]
|
|
64
|
+
# A list of permission sets to activate if the user has the role indicated by role_name
|
|
65
|
+
def assign_permissions(role_name, permission_sets)
|
|
66
|
+
name = role_name.to_s
|
|
67
|
+
|
|
68
|
+
roles[name].permission_sets.concat permission_sets
|
|
69
|
+
roles[name]
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ibrain
|
|
4
|
+
# == An ActiveModel Email Validator
|
|
5
|
+
#
|
|
6
|
+
# === Usage
|
|
7
|
+
#
|
|
8
|
+
# require 'ibrain/core/validators/email'
|
|
9
|
+
#
|
|
10
|
+
# class Person < ApplicationRecord
|
|
11
|
+
# validates :email_address, 'ibrain/email' => true
|
|
12
|
+
# end
|
|
13
|
+
#
|
|
14
|
+
class EmailValidator < ActiveModel::EachValidator
|
|
15
|
+
EMAIL_REGEXP = URI::MailTo::EMAIL_REGEXP
|
|
16
|
+
|
|
17
|
+
def validate_each(record, attribute, value)
|
|
18
|
+
unless EMAIL_REGEXP.match? value
|
|
19
|
+
record.errors.add(attribute, :invalid, **{ value: value }.merge!(options))
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ibrain
|
|
4
|
+
VERSION = "0.1.0"
|
|
5
|
+
|
|
6
|
+
def self.ibrain_version
|
|
7
|
+
VERSION
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def self.previous_ibrain_minor_version
|
|
11
|
+
'0.1.0'
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.ibrain_gem_version
|
|
15
|
+
Gem::Version.new(ibrain_version)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ibrain
|
|
4
|
+
module Core
|
|
5
|
+
# Wrapper for a value that can be different depending on the Ibrain version
|
|
6
|
+
#
|
|
7
|
+
# Some configuration defaults can be added or changed when a new Ibrain
|
|
8
|
+
# version is released. This class encapsulates getting the correct value for a
|
|
9
|
+
# given Ibrain version.
|
|
10
|
+
#
|
|
11
|
+
# The way it works is you provide an initial value in time, plus the version
|
|
12
|
+
# boundary where it got changed. Then you can fetch the value providing the
|
|
13
|
+
# desired Ibrain version:
|
|
14
|
+
#
|
|
15
|
+
# @example
|
|
16
|
+
# value = VersionedValue.new(true, "3.0.0" => false)
|
|
17
|
+
# value.call("2.7.0") # => true
|
|
18
|
+
# value.call("3.0.0") # => false
|
|
19
|
+
# value.call("3.1.0") # => false
|
|
20
|
+
#
|
|
21
|
+
# Remember that you must provide the exact boundary when a value got changed,
|
|
22
|
+
# which could easily be during a pre-release:
|
|
23
|
+
#
|
|
24
|
+
# @example
|
|
25
|
+
# value = VersionedValue.new(true, "3.0.0" => false)
|
|
26
|
+
# value.call("3.0.0.alpha") # => true
|
|
27
|
+
#
|
|
28
|
+
# value = VersionedValue.new(true, "3.0.0.alpha" => false)
|
|
29
|
+
# value.call("3.0.0.alpha") # => false
|
|
30
|
+
#
|
|
31
|
+
# Multiple boundaries can also be provided:
|
|
32
|
+
#
|
|
33
|
+
# @example
|
|
34
|
+
# value = VersionedValue.new(0, "2.0.0" => 1, "3.0.0" => 2)
|
|
35
|
+
# value.call("1.0.0") # => 0
|
|
36
|
+
# value.call("2.1.0") # => 1
|
|
37
|
+
# value.call("3.0.0") # => 2
|
|
38
|
+
class VersionedValue
|
|
39
|
+
attr_reader :boundaries
|
|
40
|
+
|
|
41
|
+
# @param initial_value [Any]
|
|
42
|
+
# @param boundary [Hash<String, Any>] Map from version number to new value
|
|
43
|
+
def initialize(initial_value, boundaries = {})
|
|
44
|
+
@boundaries = { '0' => initial_value }
|
|
45
|
+
.merge(boundaries)
|
|
46
|
+
.transform_keys { |version| to_gem_version(version) }
|
|
47
|
+
.sort.to_h
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# @param ibrain_version [String]
|
|
51
|
+
def call(ibrain_version = Ibrain.ibrain_version)
|
|
52
|
+
ibrain_version = to_gem_version(ibrain_version)
|
|
53
|
+
boundaries.fetch(
|
|
54
|
+
boundaries
|
|
55
|
+
.keys
|
|
56
|
+
.reduce do |target, following|
|
|
57
|
+
if target <= ibrain_version && ibrain_version < following
|
|
58
|
+
target
|
|
59
|
+
else
|
|
60
|
+
following
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
|
|
68
|
+
def to_gem_version(string)
|
|
69
|
+
Gem::Version.new(string)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
data/lib/ibrain/core.rb
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "action_controller/railtie"
|
|
4
|
+
require "action_mailer/railtie"
|
|
5
|
+
require "active_job/railtie"
|
|
6
|
+
require "active_model/railtie"
|
|
7
|
+
require "active_record/railtie"
|
|
8
|
+
require "active_storage/engine"
|
|
9
|
+
require 'activerecord/session_store'
|
|
10
|
+
|
|
11
|
+
require 'awesome_nested_set'
|
|
12
|
+
require 'cancan'
|
|
13
|
+
require 'friendly_id'
|
|
14
|
+
require 'kaminari/activerecord'
|
|
15
|
+
require 'rack/cors'
|
|
16
|
+
require 'ransack'
|
|
17
|
+
|
|
18
|
+
module Ibrain
|
|
19
|
+
mattr_accessor :user_class
|
|
20
|
+
|
|
21
|
+
def self.user_class
|
|
22
|
+
case @@user_class
|
|
23
|
+
when Class
|
|
24
|
+
raise "Ibrain.user_class MUST be a String or Symbol object, not a Class object."
|
|
25
|
+
when String, Symbol
|
|
26
|
+
@@user_class.to_s.constantize
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Load the same version defaults for all available Ibrain components
|
|
31
|
+
#
|
|
32
|
+
# @see Ibrain::Preferences::Configuration#load_defaults
|
|
33
|
+
def self.load_defaults(version)
|
|
34
|
+
Ibrain::Config.load_defaults(version)
|
|
35
|
+
Ibrain::Api::Config.load_defaults(version) if defined?(Ibrain::Api::Config)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Used to configure Ibrain.
|
|
39
|
+
#
|
|
40
|
+
# Example:
|
|
41
|
+
#
|
|
42
|
+
# Ibrain.config do |config|
|
|
43
|
+
# config.track_inventory_levels = false
|
|
44
|
+
# end
|
|
45
|
+
#
|
|
46
|
+
# This method is defined within the core gem on purpose.
|
|
47
|
+
# Some people may only wish to use the Core part of Ibrain.
|
|
48
|
+
def self.config(&_block)
|
|
49
|
+
yield(Ibrain::Config)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
module Core
|
|
53
|
+
def self.does_ibrain_initializer_exist?(rails_paths, initializer_name)
|
|
54
|
+
rails_paths['config/initializers'].any? do |path|
|
|
55
|
+
File.exist?(Pathname.new(path).join(initializer_name))
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
private_class_method :does_ibrain_initializer_exist?
|
|
60
|
+
|
|
61
|
+
class GatewayError < RuntimeError; end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
require "ibrain/core/version"
|
|
66
|
+
|
|
67
|
+
require 'ibrain/core/class_constantizer'
|
|
68
|
+
require 'ibrain/core/environment_extension'
|
|
69
|
+
require 'ibrain/core/environment'
|
|
70
|
+
|
|
71
|
+
require "ibrain/core/engine"
|
|
72
|
+
|
|
73
|
+
require 'ibrain/i18n'
|
|
74
|
+
require 'ibrain/permitted_attributes'
|
|
75
|
+
require 'ibrain/permission_sets'
|
|
76
|
+
require 'ibrain/logger'
|
|
77
|
+
|
|
78
|
+
require 'ibrain/core/controller_helpers/response'
|
|
79
|
+
require 'ibrain/core/controller_helpers/current_host'
|
|
80
|
+
require 'ibrain/core/controller_helpers/strong_parameters'
|
|
81
|
+
require 'ibrain/core/controller_helpers/auth'
|
|
82
|
+
require 'ibrain/core/role_configuration'
|
|
83
|
+
|
|
84
|
+
require 'ibrain/core/validators/email'
|
|
85
|
+
require 'ibrain/user_class_handle'
|
|
86
|
+
require 'ibrain/encryptor'
|