ibrain-core 0.1.6 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f097ac075d8648653298078113ae7d36b8b9058b8a06dd93d450c6c1126ea1fc
4
- data.tar.gz: 9dcdccbb0202e258a67d1f7373e2abb329f47fc6e2ad94faccd832e489a19c82
3
+ metadata.gz: 1a04fdcab0c02b1f8a8d58a25dae8cd1bda74a4b296e2aeb219861df4464f008
4
+ data.tar.gz: baae07824103dcc3c80ab8228b154009242bca6648f3706ab9d5e18f743c9303
5
5
  SHA512:
6
- metadata.gz: 49610235d7470b0634732e8f47c40d12d6e80cfeff70fa676b586883e251b2a125367ee34232e49c79456910e679827b1597a16b8aabe1a4dc4266c6d10bbf81
7
- data.tar.gz: 137dbd8406dc08d92624cf78e0c8732b31b89507a39372cd0215d2ed6e3514d990f4ab90da097a45861cf351228e9c33af3bb9373561a2a9deab2790c2300e4c
6
+ metadata.gz: 4e1d2b42216cdffccbc7e5b1b103f9370c5dc8486a2a30ee5a902295a72c5d606e23881d110bb63715e105c2270834515c931ad49abbd6888437cf34ec97dda3
7
+ data.tar.gz: cdbc90d0ddaed7d02d76ad69061e84cbd7bc4b6dcfaf82ce4035f994189fbeece3c5452098393e4efdf85a4700b120ed1df8d25fea612fdcd4ce93b2e0b47694
data/README.md CHANGED
@@ -54,20 +54,34 @@ bundle exec rails generate ibrain:graphql:resolvers users --model=User
54
54
  For pagination please using aggregate body query, something like
55
55
  ```
56
56
  query users($offset: Int, $limit: Int, $filter: Filter) {
57
- users(offset: $offset, limit: $limit, filter: $filter) {
58
- id
59
- first_name
60
- }
57
+ users(offset: $offset, limit: $limit, filter: $filter) {
58
+ id
59
+ first_name
60
+ }
61
61
 
62
- users_aggregate(filter: $filter) {
63
- total_count
64
- }
62
+ users_aggregate(filter: $filter) {
63
+ total_count
64
+ }
65
65
  }
66
66
  ```
67
67
  To generate graphql mutation to insert, update, delete user
68
68
  ```bash
69
69
  bundle exec rails generate ibrain:graphql:mutation insert_user --model=User
70
70
  ```
71
+
72
+ Default all operation will be rejected if you not have Authorization Token at request header, so to skip authenticate please change `parent_controller` at `ibrain.rb`
73
+ ```
74
+ config.parent_controller = "<Your parent controller>"
75
+ ```
76
+ then create method skip_operations at this parent_controller
77
+ ```
78
+ class ApplicationController < BaseController::API
79
+ def skip_operations
80
+ %w[sign_in].include?(operation_name)
81
+ end
82
+ end
83
+ ```
84
+
71
85
  ## Contributing
72
86
  Contribution directions go here.
73
87
 
@@ -12,6 +12,7 @@ module IbrainHandler
12
12
  rescue_from IbrainErrors::UnknownError, with: :bad_request_handler
13
13
  rescue_from ActionController::InvalidAuthenticityToken, with: :unauthorized_handler
14
14
  rescue_from ActiveSupport::MessageVerifier::InvalidSignature, with: :unauthorized_handler
15
+ rescue_from GraphQL::ExecutionError, with: :bad_request_handler
15
16
  end
16
17
 
17
18
  private
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Ibrain
4
- class BaseController < ActionController::API
4
+ class BaseController < Ibrain::Config.parent_controller.constantize
5
5
  include ActionController::Helpers
6
6
  include Ibrain::Core::ControllerHelpers::Response
7
7
  include Ibrain::Core::ControllerHelpers::StrongParameters
@@ -18,7 +18,7 @@ module Ibrain
18
18
  end
19
19
 
20
20
  def skip_operations
21
- []
21
+ super || ['IntrospectionQuery'].include?(operation_name)
22
22
  end
23
23
 
24
24
  def cryptor
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ibrain
4
+ module Core
5
+ class GraphqlController < ::Ibrain::BaseController
6
+ include Devise::Controllers::ScopedViews
7
+
8
+ before_action :authenticate_user!, unless: :skip_operations
9
+ before_action :map_user_class_to_request
10
+
11
+ helpers = %w(resource scope_name resource_name signed_in_resource
12
+ resource_class resource_params devise_mapping)
13
+ helper_method(*helpers)
14
+
15
+ def execute
16
+ query, variables, operation_name = normalize_entity
17
+
18
+ result = schema.execute(
19
+ query,
20
+ variables: variables,
21
+ context: {
22
+ session: session,
23
+ current_user: try_ibrain_current_user,
24
+ controller: self,
25
+ request: request
26
+ },
27
+ operation_name: operation_name
28
+ )
29
+
30
+ render_json_ok(result['data'], nil, result['errors'])
31
+ end
32
+
33
+ protected
34
+
35
+ def normalize_entity
36
+ query = params[:query]
37
+ operation_name = params[:operationName]
38
+ variables = prepare_variables(params[:variables])
39
+
40
+ [query, variables, operation_name]
41
+ end
42
+
43
+ # Handle variables in form data, JSON body, or a blank value
44
+ def prepare_variables(variables_param)
45
+ case variables_param
46
+ when String
47
+ if variables_param.present?
48
+ JSON.parse(variables_param) || {}
49
+ else
50
+ {}
51
+ end
52
+ when Hash
53
+ variables_param
54
+ when ActionController::Parameters
55
+ variables_param.to_unsafe_hash # GraphQLRuby will validate name and type of incoming variables.
56
+ when nil
57
+ {}
58
+ else
59
+ raise ArgumentError, "Unexpected parameter: #{variables_param}"
60
+ end
61
+ end
62
+
63
+ def schema
64
+ Ibrain::Config.graphql_schema.safe_constantize
65
+ end
66
+
67
+ def map_user_class_to_request
68
+ return if request.env['devise.mapping'].present?
69
+
70
+ request.env['devise.mapping'] = Ibrain.user_class
71
+ end
72
+ end
73
+ end
74
+ end
@@ -6,7 +6,7 @@ module Ibrain
6
6
 
7
7
  use GraphQL::Guard.new(
8
8
  policy_object: ::Ibrain::Config.graphql_policy.safe_constantize,
9
- not_authorized: ->(type, field) { GraphQL::ExecutionError.new("Not authorized to access #{type}.#{field}") }
9
+ not_authorized: ->(type, field) { raise IbrainErrors::UnknownError.new("Not authorized to access #{type}.#{field}") }
10
10
  )
11
11
 
12
12
  # Union and Interface Resolution
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Ibrain
4
4
  module Lazy
5
- class Base < GraphQL::Function
5
+ class Base < GraphQL::Schema::Resolver
6
6
  end
7
7
  end
8
8
  end
@@ -30,6 +30,18 @@ module Ibrain
30
30
  def current_user
31
31
  context[:current_user]
32
32
  end
33
+
34
+ def controller
35
+ context[:controller]
36
+ end
37
+
38
+ def session
39
+ context[:session]
40
+ end
41
+
42
+ def request
43
+ context[:request]
44
+ end
33
45
  end
34
46
  end
35
47
  end
@@ -3,26 +3,32 @@
3
3
  module Ibrain
4
4
  module Policies
5
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
6
  class << self
7
+ def query_rules
8
+ {
9
+ '*': {
10
+ guard: ->(_obj, _args, _ctx) { false }
11
+ }
12
+ }
13
+ end
14
+
15
+ def mutation_rules
16
+ {
17
+ '*': {
18
+ guard: ->(_obj, _args, _ctx) { false }
19
+ }
20
+ }
21
+ end
22
+
23
+ def rules
24
+ {
25
+ 'Types::QueryType' => query_rules,
26
+ 'Types::MutationType' => mutation_rules
27
+ }.freeze
28
+ end
29
+
24
30
  def roles
25
- Ibrain::Config.ibrain_roles
31
+ Ibrain.user_class.roles.keys
26
32
  end
27
33
 
28
34
  def has_permission?(current_user, resource)
@@ -33,11 +39,11 @@ module Ibrain
33
39
  end
34
40
 
35
41
  def guard(type, field)
36
- RULES.dig(type.name, field, :guard)
42
+ rules.dig(type.name, field, :guard)
37
43
  end
38
44
 
39
45
  def not_authorized_handler(type, field)
40
- RULES.dig(type, field, :not_authorized) || RULES.dig(type, :*, :not_authorized)
46
+ rules.dig(type, field, :not_authorized) || rules.dig(type, :*, :not_authorized)
41
47
  end
42
48
  end
43
49
  end
@@ -10,6 +10,10 @@ module Ibrain
10
10
  def current_user
11
11
  context.fetch(:current_user)
12
12
  end
13
+
14
+ def controller
15
+ context[:controller]
16
+ end
13
17
  end
14
18
  end
15
19
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Ibrain::Types::BaseNode < Types::BaseObject
3
+ class Ibrain::Types::BaseNode < Ibrain::Types::BaseObject
4
4
  include ::GraphQL::Relay::Node
5
5
  implements ::Ibrain::Interfaces::RecordInterface
6
6
 
@@ -5,10 +5,8 @@ module Ibrain
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  include Ibrain::UserApiAuthentication
8
- include Ibrain::UserReporting
9
8
 
10
9
  included do
11
- extend Ibrain::DisplayMoney
12
10
  after_create :auto_generate_ibrain_api_key
13
11
 
14
12
  include Ibrain::RansackableAttributes unless included_modules.include?(Ibrain::RansackableAttributes)
@@ -6,7 +6,7 @@ module Ibrain
6
6
  # @note This class is intended to be modified by extensions (ex.
7
7
  # ibrain-auth)
8
8
  class LegacyUser < Ibrain::Base
9
- include UserMethods
9
+ include Ibrain::UserMethods
10
10
 
11
11
  self.table_name = 'ibrain_users'
12
12
 
data/config/routes.rb CHANGED
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  Ibrain::Core::Engine.routes.draw do
4
- if ::Ibrain::Config.api_version.blank?
5
- post '/api/graphql', to: 'graphql#execute'
6
- else
7
- post "/api/#{::Ibrain::Config.api_version.downcase}/graphql", controller: 'graphql', action: 'execute'
8
- end
4
+ post "/", controller: 'graphql', action: 'execute'
9
5
  end
@@ -7,7 +7,7 @@ module Resolvers
7
7
  # description
8
8
 
9
9
  # TODO: define return fields
10
- type Types::Objects::<%= model_name.capitalize %>Type, null: false, description: 'Define data type will be response to client'
10
+ type Types::Objects::<%= model_name.capitalize %>Type, null: false
11
11
 
12
12
  argument :id, ID, required: false, description: 'TODO: describe about this argument'
13
13
 
@@ -7,7 +7,7 @@ module Resolvers
7
7
  # description
8
8
 
9
9
  # TODO: define return fields
10
- type [Types::Objects::<%= model_name.capitalize %>Type], null: false, description: 'Define data type will be response to client'
10
+ type [Types::Objects::<%= model_name.capitalize %>Type], null: false
11
11
 
12
12
  # TODO: define resolve method
13
13
  def resolve(args)
@@ -41,6 +41,9 @@ Ibrain.config do |config|
41
41
 
42
42
  # Graphql Encryptor key
43
43
  # config.ibrain_encryptor_key = Rails.application.secrets.secret_key_base.byteslice(0..31)
44
+
45
+ # Parent controller
46
+ # config.parent_controller = 'ActionController::API'
44
47
  end
45
48
 
46
49
  <% if defined?(Ibrain::Api::Engine) -%>
@@ -48,6 +48,9 @@ module Ibrain
48
48
  # Graphql Encryptor key
49
49
  preference :ibrain_encryptor_key, :string, default: nil
50
50
 
51
+ # Parent controller
52
+ preference :parent_controller, :string, default: 'ActionController::API'
53
+
51
54
  def static_model_preferences
52
55
  @static_model_preferences ||= Ibrain::Preferences::StaticModelPreferences.new
53
56
  end
@@ -16,6 +16,7 @@ module Ibrain
16
16
  def render_json_error(error, status)
17
17
  e_message = error.try(:record).try(:errors).try(:full_messages).try(:first)
18
18
  e_message = error.try(:message) if e_message.blank?
19
+ e_message = error.try(:details) if e_message.blank?
19
20
 
20
21
  backtrace = error.try(:backtrace).try(:join, "\n")
21
22
 
@@ -5,7 +5,7 @@ require 'ibrain/config'
5
5
  module Ibrain
6
6
  module Core
7
7
  class Engine < ::Rails::Engine
8
- isolate_namespace Ibrain
8
+ isolate_namespace Ibrain::Core
9
9
  config.generators.api_only = true
10
10
 
11
11
  initializer "ibrain.environment", before: :load_config_initializers do |app|
@@ -1,14 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Ibrain
4
- VERSION = "0.1.6"
4
+ VERSION = "0.2.0"
5
5
 
6
6
  def self.ibrain_version
7
7
  VERSION
8
8
  end
9
9
 
10
10
  def self.previous_ibrain_minor_version
11
- '0.1.5'
11
+ '0.1.9'
12
12
  end
13
13
 
14
14
  def self.ibrain_gem_version
data/lib/ibrain/core.rb CHANGED
@@ -14,6 +14,7 @@ require 'friendly_id'
14
14
  require 'kaminari/activerecord'
15
15
  require 'rack/cors'
16
16
  require 'ransack'
17
+ require 'discard'
17
18
 
18
19
  module Ibrain
19
20
  mattr_accessor :user_class
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ibrain-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tai Nguyen Van
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-30 00:00:00.000000000 Z
11
+ date: 2022-01-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord-session_store
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: 1.15.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: discard
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.2'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.2'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: friendly_id
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -169,7 +183,7 @@ files:
169
183
  - app/controllers/concerns/ibrain_errors.rb
170
184
  - app/controllers/concerns/ibrain_handler.rb
171
185
  - app/controllers/ibrain/base_controller.rb
172
- - app/controllers/ibrain/graphql_controller.rb
186
+ - app/controllers/ibrain/core/graphql_controller.rb
173
187
  - app/graphql/ibrain/base_schema.rb
174
188
  - app/graphql/ibrain/extentions/default_value.rb
175
189
  - app/graphql/ibrain/interfaces/base_interface.rb
@@ -200,14 +214,13 @@ files:
200
214
  - app/graphql/ibrain/types/node_type.rb
201
215
  - app/graphql/ibrain/util/field_combiner.rb
202
216
  - app/graphql/ibrain/util/query_combiner.rb
203
- - app/graphql/mutations/insert_user.rb
217
+ - app/models/concerns/ibrain/ransackable_attributes.rb
218
+ - app/models/concerns/ibrain/soft_deletable.rb
219
+ - app/models/concerns/ibrain/user_api_authentication.rb
220
+ - app/models/concerns/ibrain/user_methods.rb
204
221
  - app/models/ibrain/ability.rb
205
222
  - app/models/ibrain/application_record.rb
206
223
  - app/models/ibrain/base.rb
207
- - app/models/ibrain/concerns/ransackable_attributes.rb
208
- - app/models/ibrain/concerns/soft_deletable.rb
209
- - app/models/ibrain/concerns/user_api_authentication.rb
210
- - app/models/ibrain/concerns/user_methods.rb
211
224
  - app/models/ibrain/legacy_user.rb
212
225
  - app/models/ibrain/role.rb
213
226
  - app/models/ibrain/role_user.rb
@@ -1,55 +0,0 @@
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: try_ibrain_current_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
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Ibrain
4
- module Mutations
5
- class InsertUser < Ibrain::Mutations::BaseMutation
6
- # TODO: define return fields
7
- # field :post, Types::PostType, null: false
8
-
9
- # TODO: define arguments
10
- # argument :name, String, required: true
11
-
12
- # TODO: define resolve method
13
- # def resolve(name:)
14
- # { post: ... }
15
- # end
16
- end
17
- end
18
- end