ibrain-core 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e306b2238fba539d079c52bbb0c6b6bb2ff1092e9f950c4c6fd85065b2325fa3
|
4
|
+
data.tar.gz: d9ae60e6b5769f14339bcdba97ed42538523c34aa9d382454496d0ac49f1d320
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3ae2d1c79c5931769a432d6532f104c88245afb7df5dc3d0af557b3496b215548cbae686203f229c7d5bac7226000e39caad0ffe42fae0361fe19b1ca64f38df
|
7
|
+
data.tar.gz: 6b34268ff18f1eb0daafcd47d2b7a32f48360370ddc7367c18d5399048b69ca391758b4e0fdaa137a3a6f9d73d7cf02c84d828fe000a0ba7911d99d934dabe7e
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2021 TODO: Write your name
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
# Ibrain::Core
|
2
|
+
This is core plugin for rails api project
|
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 'ibrain-core'
|
12
|
+
```
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
```bash
|
16
|
+
$ bundle
|
17
|
+
```
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
```bash
|
21
|
+
$ gem install ibrain-core
|
22
|
+
```
|
23
|
+
|
24
|
+
Please install plugin after install this gem
|
25
|
+
```bash
|
26
|
+
$ bundle exec rails generate ibrain:install
|
27
|
+
```
|
28
|
+
# Migration
|
29
|
+
Default migration engine is [ridgepole](https://github.com/ridgepole/ridgepole), using this command line to migrate database:
|
30
|
+
```bash
|
31
|
+
bundle exec rails ridgpole:apply
|
32
|
+
```
|
33
|
+
To use default migration plugin, please disable ridgepole
|
34
|
+
```bash
|
35
|
+
bundle exec rails generate ibrain::install --with-ridgepole=false
|
36
|
+
```
|
37
|
+
# GraphQL API
|
38
|
+
If you use graphql for rails please add this option when install plugin
|
39
|
+
```bash
|
40
|
+
$ bundle exec rails generate ibrain::install --with-graphql
|
41
|
+
```
|
42
|
+
To generate graphql type
|
43
|
+
```bash
|
44
|
+
bundle exec rails generate ibrain:graphql:object user
|
45
|
+
```
|
46
|
+
To generate graphql resolver single query to get user data
|
47
|
+
```bash
|
48
|
+
bundle exec rails generate ibrain:graphql:resolver user --model=User
|
49
|
+
```
|
50
|
+
To generate graphql resolvers query to get users list
|
51
|
+
```bash
|
52
|
+
bundle exec rails generate ibrain:graphql:resolvers users --model=User
|
53
|
+
```
|
54
|
+
For pagination please using aggregate body query, something like
|
55
|
+
```
|
56
|
+
query users($offset: Int, $limit: Int, $filter: Filter) {
|
57
|
+
users(offset: $offset, limit: $limit, filter: $filter) {
|
58
|
+
id
|
59
|
+
first_name
|
60
|
+
}
|
61
|
+
|
62
|
+
users_aggregate(filter: $filter) {
|
63
|
+
total_count
|
64
|
+
}
|
65
|
+
}
|
66
|
+
```
|
67
|
+
To generate graphql mutation to insert, update, delete user
|
68
|
+
```bash
|
69
|
+
bundle exec rails generate ibrain:graphql:mutation insert_user --model=User
|
70
|
+
```
|
71
|
+
## Contributing
|
72
|
+
Contribution directions go here.
|
73
|
+
|
74
|
+
## License
|
75
|
+
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,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module IbrainErrors
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
class PermissionError < StandardError; end
|
7
|
+
|
8
|
+
class UnknownError < StandardError
|
9
|
+
def initialize(message)
|
10
|
+
super
|
11
|
+
|
12
|
+
@message = message
|
13
|
+
end
|
14
|
+
|
15
|
+
def details
|
16
|
+
message
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
attr_accessor :message
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module IbrainHandler
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
rescue_from StandardError, with: :standard_handler
|
8
|
+
rescue_from ActionController::ParameterMissing, with: :parameter_handler
|
9
|
+
rescue_from ActiveRecord::RecordNotFound, with: :not_found_handler
|
10
|
+
rescue_from ActiveRecord::RecordInvalid, with: :bad_request_handler
|
11
|
+
rescue_from IbrainErrors::PermissionError, with: :permission_denied_handler
|
12
|
+
rescue_from IbrainErrors::UnknownError, with: :bad_request_handler
|
13
|
+
rescue_from ActionController::InvalidAuthenticityToken, with: :unauthorized_handler
|
14
|
+
rescue_from ActiveSupport::MessageVerifier::InvalidSignature, with: :unauthorized_handler
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def standard_handler(errors)
|
20
|
+
render_json_error(errors, 500)
|
21
|
+
end
|
22
|
+
|
23
|
+
def bad_request_handler(errors)
|
24
|
+
render_json_error(errors, 400)
|
25
|
+
end
|
26
|
+
|
27
|
+
def parameter_handler(errors)
|
28
|
+
render_json_error(errors, 400)
|
29
|
+
end
|
30
|
+
|
31
|
+
def not_found_handler(errors)
|
32
|
+
render_json_error(errors, 404)
|
33
|
+
end
|
34
|
+
|
35
|
+
def permission_denied_handler(errors)
|
36
|
+
render_json_error(errors, 405)
|
37
|
+
end
|
38
|
+
|
39
|
+
def unauthorized_handler(errors)
|
40
|
+
render_json_error(errors, 401)
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Ibrain
|
4
|
+
class BaseController < ActionController::API
|
5
|
+
include ActionController::Helpers
|
6
|
+
include Ibrain::Core::ControllerHelpers::Response
|
7
|
+
include Ibrain::Core::ControllerHelpers::StrongParameters
|
8
|
+
include Ibrain::Core::ControllerHelpers::CurrentHost
|
9
|
+
include Ibrain::Core::ControllerHelpers::Auth
|
10
|
+
|
11
|
+
include IbrainErrors
|
12
|
+
include IbrainHandler
|
13
|
+
|
14
|
+
protected
|
15
|
+
|
16
|
+
def operation_name
|
17
|
+
params[:operationName]
|
18
|
+
end
|
19
|
+
|
20
|
+
def skip_operations
|
21
|
+
[]
|
22
|
+
end
|
23
|
+
|
24
|
+
def cryptor
|
25
|
+
Ibrain::Encryptor.new
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Ibrain
|
4
|
+
class GraphqlController < Ibrain::BaseController
|
5
|
+
def execute
|
6
|
+
query, variables, operation_name = normalize_entity
|
7
|
+
|
8
|
+
result = schema.execute(
|
9
|
+
query,
|
10
|
+
variables: variables,
|
11
|
+
context: {
|
12
|
+
session: session,
|
13
|
+
current_user: current_ibrain_user
|
14
|
+
},
|
15
|
+
operation_name: operation_name
|
16
|
+
)
|
17
|
+
|
18
|
+
render_json_ok(result['data'], nil, result['errors'])
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
|
23
|
+
def normalize_entity
|
24
|
+
query = params[:query]
|
25
|
+
operation_name = params[:operationName]
|
26
|
+
variables = prepare_variables(params[:variables])
|
27
|
+
|
28
|
+
[query, variables, operation_name]
|
29
|
+
end
|
30
|
+
|
31
|
+
# Handle variables in form data, JSON body, or a blank value
|
32
|
+
def prepare_variables(variables_param)
|
33
|
+
case variables_param
|
34
|
+
when String
|
35
|
+
if variables_param.present?
|
36
|
+
JSON.parse(variables_param) || {}
|
37
|
+
else
|
38
|
+
{}
|
39
|
+
end
|
40
|
+
when Hash
|
41
|
+
variables_param
|
42
|
+
when ActionController::Parameters
|
43
|
+
variables_param.to_unsafe_hash # GraphQLRuby will validate name and type of incoming variables.
|
44
|
+
when nil
|
45
|
+
{}
|
46
|
+
else
|
47
|
+
raise ArgumentError, "Unexpected parameter: #{variables_param}"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def schema
|
52
|
+
Ibrain::Config.graphql_schema.safe_constantize
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Ibrain
|
4
|
+
class BaseSchema < ::GraphQL::Schema
|
5
|
+
use GraphQL::Batch
|
6
|
+
|
7
|
+
use GraphQL::Guard.new(
|
8
|
+
policy_object: ::Ibrain::Config.graphql_policy.safe_constantize,
|
9
|
+
not_authorized: ->(type, field) { GraphQL::ExecutionError.new("Not authorized to access #{type}.#{field}") }
|
10
|
+
)
|
11
|
+
|
12
|
+
# Union and Interface Resolution
|
13
|
+
def self.resolve_type(_abstract_type, _obj, _ctx)
|
14
|
+
# TODO: Implement this function
|
15
|
+
# to return the correct object type for `obj`
|
16
|
+
raise(GraphQL::RequiredImplementationMissingError)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Relay-style Object Identification:
|
20
|
+
|
21
|
+
# Return a string UUID for `object`
|
22
|
+
def self.id_from_object(object, type_definition, query_ctx)
|
23
|
+
# Here's a simple implementation which:
|
24
|
+
# - joins the type name & object.id
|
25
|
+
# - encodes it with base64:
|
26
|
+
# GraphQL::Schema::UniqueWithinType.encode(type_definition.name, object.id)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Given a string UUID, find the object
|
30
|
+
def self.object_from_id(id, query_ctx)
|
31
|
+
# For example, to decode the UUIDs generated above:
|
32
|
+
# type_name, item_id = GraphQL::Schema::UniqueWithinType.decode(id)
|
33
|
+
#
|
34
|
+
# Then, based on `type_name` and `id`
|
35
|
+
# find an object in your application
|
36
|
+
# ...
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.field(*args, camelize: false, **kwargs, &block)
|
40
|
+
# if camelize == false
|
41
|
+
# # Also make a camelized field:
|
42
|
+
# field(*args, camelize: false, **kwargs, &block)
|
43
|
+
# end
|
44
|
+
super
|
45
|
+
end
|
46
|
+
|
47
|
+
rescue_from(ActiveRecord::RecordNotFound) do |_err, _obj, _args, _ctx, field|
|
48
|
+
# Raise a graphql-friendly error with a custom message
|
49
|
+
raise GraphQL::ExecutionError, "#{field.type.unwrap.graphql_name} not found"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Ibrain
|
4
|
+
module Extentions
|
5
|
+
class DefaultValue < GraphQL::Schema::FieldExtension
|
6
|
+
def after_resolve(value:, **_rest)
|
7
|
+
if value.nil?
|
8
|
+
options[:default_value]
|
9
|
+
else
|
10
|
+
value
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Ibrain::Interfaces::PersonInterface
|
4
|
+
include Ibrain::Types::BaseInterface
|
5
|
+
|
6
|
+
description 'Person Interface'
|
7
|
+
|
8
|
+
field :first_name, String, null: true
|
9
|
+
field :last_name, String, null: true
|
10
|
+
field :full_name, String, null: true
|
11
|
+
|
12
|
+
def full_name
|
13
|
+
[object.try(:first_name), object.try(:last_name)].compact.join(' ')
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Ibrain::Interfaces::RecordInterface
|
4
|
+
include Ibrain::Types::BaseInterface
|
5
|
+
|
6
|
+
description 'Common Interface'
|
7
|
+
|
8
|
+
field :created_at, ::GraphQL::Types::ISO8601DateTime, null: false
|
9
|
+
field :updated_at, ::GraphQL::Types::ISO8601DateTime, null: false
|
10
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# ref: https://zenn.dev/necocoa/articles/setup-graphql-batch
|
4
|
+
|
5
|
+
module Ibrain
|
6
|
+
module Loaders
|
7
|
+
class AssociationLoader < GraphQL::Batch::Loader
|
8
|
+
def self.validate(model, association_name)
|
9
|
+
new(model, association_name)
|
10
|
+
nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(model, association_name)
|
14
|
+
super()
|
15
|
+
@model = model
|
16
|
+
@association_name = association_name
|
17
|
+
validate
|
18
|
+
end
|
19
|
+
|
20
|
+
def load(record)
|
21
|
+
unless record.is_a?(@model)
|
22
|
+
raise TypeError,
|
23
|
+
"#{@model} loader can't load association for #{record.class}"
|
24
|
+
end
|
25
|
+
return Promise.resolve(read_association(record)) if association_loaded?(record)
|
26
|
+
|
27
|
+
super
|
28
|
+
end
|
29
|
+
|
30
|
+
# We want to load the associations on all records, even if they have the same id
|
31
|
+
def cache_key(record)
|
32
|
+
record.object_id
|
33
|
+
end
|
34
|
+
|
35
|
+
def perform(records)
|
36
|
+
preload_association(records)
|
37
|
+
records.each { |record| fulfill(record, read_association(record)) }
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def validate
|
43
|
+
return if @model.reflect_on_association(@association_name)
|
44
|
+
|
45
|
+
raise ArgumentError, "No association #{@association_name} on #{@model}"
|
46
|
+
end
|
47
|
+
|
48
|
+
def preload_association(records)
|
49
|
+
::ActiveRecord::Associations::Preloader.new.preload(records, @association_name)
|
50
|
+
end
|
51
|
+
|
52
|
+
def read_association(record)
|
53
|
+
record.public_send(@association_name)
|
54
|
+
end
|
55
|
+
|
56
|
+
def association_loaded?(record)
|
57
|
+
record.association(@association_name).loaded?
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Ibrain
|
4
|
+
module Mutations
|
5
|
+
class BaseMutation < GraphQL::Schema::RelayClassicMutation
|
6
|
+
argument_class Types::BaseArgument
|
7
|
+
field_class Types::BaseField
|
8
|
+
input_object_class Types::BaseInputObject
|
9
|
+
object_class Types::BaseObject
|
10
|
+
|
11
|
+
argument :attribute, Types::AttributeType, required: false
|
12
|
+
argument :attributes, [Types::AttributeType], required: false
|
13
|
+
|
14
|
+
def resolve(args)
|
15
|
+
@params = ::ActionController::Parameters.new(args)
|
16
|
+
end
|
17
|
+
|
18
|
+
protected
|
19
|
+
|
20
|
+
attr_reader :params
|
21
|
+
|
22
|
+
def upload_permitted
|
23
|
+
%i[content_type headers original_filename tempfile]
|
24
|
+
end
|
25
|
+
|
26
|
+
def cryptor
|
27
|
+
::Ibrain::Encryptor.new
|
28
|
+
end
|
29
|
+
|
30
|
+
def current_user
|
31
|
+
context[:current_user]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Ibrain
|
4
|
+
module Policies
|
5
|
+
class BasePolicy
|
6
|
+
IBRAIN_QUERY_RULES = {
|
7
|
+
'*': {
|
8
|
+
guard: ->(_obj, _args, _ctx) { true }
|
9
|
+
}
|
10
|
+
}
|
11
|
+
|
12
|
+
IBRAIN_MUTATION_RULES = {
|
13
|
+
'*': {
|
14
|
+
guard: ->(_obj, _args, ctx) { roles.include?(ctx[:current_user].try(:role)) }
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
RULES = {
|
19
|
+
'Query' => IBRAIN_QUERY_RULES,
|
20
|
+
'Mutation' => IBRAIN_MUTATION_RULES
|
21
|
+
}.freeze
|
22
|
+
|
23
|
+
class << self
|
24
|
+
def roles
|
25
|
+
Ibrain::Config.ibrain_roles
|
26
|
+
end
|
27
|
+
|
28
|
+
def has_permission?(current_user, resource)
|
29
|
+
return false if current_user.blank?
|
30
|
+
return true if current_user.super_admin?
|
31
|
+
|
32
|
+
current_user.try(:scope).to_s.split(',').include?(resource)
|
33
|
+
end
|
34
|
+
|
35
|
+
def guard(type, field)
|
36
|
+
RULES.dig(type.name, field, :guard)
|
37
|
+
end
|
38
|
+
|
39
|
+
def not_authorized_handler(type, field)
|
40
|
+
RULES.dig(type, field, :not_authorized) || RULES.dig(type, :*, :not_authorized)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Ibrain
|
4
|
+
module Resolvers
|
5
|
+
class BaseResolver < GraphQL::Schema::Resolver
|
6
|
+
argument :filter, Ibrain::Types::FilterType, required: false, default_value: nil
|
7
|
+
argument :offset, Int, required: false, default_value: 0
|
8
|
+
argument :limit, Int, required: false, default_value: 10
|
9
|
+
|
10
|
+
def current_user
|
11
|
+
context.fetch(:current_user)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Ibrain
|
4
|
+
module Types
|
5
|
+
class BaseConnection < Types::BaseObject
|
6
|
+
# add `nodes` and `pageInfo` fields, as well as `edge_type(...)` and `node_nullable(...)` overrides
|
7
|
+
include GraphQL::Types::Relay::ConnectionBehaviors
|
8
|
+
|
9
|
+
field :total_count, Integer, null: false, camelize: false
|
10
|
+
|
11
|
+
def total_count
|
12
|
+
object.items.size
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Ibrain
|
4
|
+
module Types
|
5
|
+
class BaseField < GraphQL::Schema::Field
|
6
|
+
argument_class ::Ibrain::Types::BaseArgument
|
7
|
+
|
8
|
+
def initialize(*args, default_value: nil, **kwargs, &block)
|
9
|
+
super(*args, camelize: false, **kwargs, &block)
|
10
|
+
|
11
|
+
extension(::Ibrain::Extentions::DefaultValue, default_value: default_value) unless default_value.nil?
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Ibrain
|
4
|
+
module Types
|
5
|
+
module BaseInterface
|
6
|
+
include GraphQL::Schema::Interface
|
7
|
+
|
8
|
+
edge_type_class(Ibrain::Types::BaseEdge)
|
9
|
+
connection_type_class(Ibrain::Types::BaseConnection)
|
10
|
+
|
11
|
+
field_class Ibrain::Types::BaseField
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Ibrain::Types::BaseNode < Types::BaseObject
|
4
|
+
implements ::GraphQL::Relay::Node.interface
|
5
|
+
implements ::Ibrain::Interfaces::RecordInterface
|
6
|
+
|
7
|
+
global_id_field :id
|
8
|
+
field_class ::Ibrain::Types::BaseField
|
9
|
+
|
10
|
+
def self.field(*args, camelize: false, **kwargs, &block)
|
11
|
+
super
|
12
|
+
end
|
13
|
+
end
|