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,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'type_generator'
|
|
4
|
+
|
|
5
|
+
module Ibrain
|
|
6
|
+
module Graphql
|
|
7
|
+
# Generate an object type by name,
|
|
8
|
+
# with the specified fields.
|
|
9
|
+
#
|
|
10
|
+
# ```
|
|
11
|
+
# rails g graphql:object PostType name:String!
|
|
12
|
+
# ```
|
|
13
|
+
#
|
|
14
|
+
# Add the Node interface with `--node`.
|
|
15
|
+
class ObjectGenerator < TypeGeneratorBase
|
|
16
|
+
desc "Create a GraphQL::ObjectType with the given name and fields." \
|
|
17
|
+
"If the given type name matches an existing ActiveRecord model, the generated type will automatically include fields for the models database columns."
|
|
18
|
+
source_root File.expand_path('templates', __dir__)
|
|
19
|
+
|
|
20
|
+
argument :custom_fields,
|
|
21
|
+
type: :array,
|
|
22
|
+
default: [],
|
|
23
|
+
banner: "name:type name:type ...",
|
|
24
|
+
desc: "Fields for this object (type may be expressed as Ruby or GraphQL)"
|
|
25
|
+
|
|
26
|
+
class_option :node,
|
|
27
|
+
type: :boolean,
|
|
28
|
+
default: false,
|
|
29
|
+
desc: "Include the Relay Node interface"
|
|
30
|
+
|
|
31
|
+
def create_type_file
|
|
32
|
+
template "object.erb", "#{options[:directory]}/types/objects/#{type_file_name}.rb"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def fields
|
|
36
|
+
columns = []
|
|
37
|
+
columns += klass.columns.map { |c| generate_column_string(c) } if class_exists?
|
|
38
|
+
columns + custom_fields
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def self.normalize_type_expression(type_expression, mode:, null: true)
|
|
42
|
+
case type_expression
|
|
43
|
+
when "Text", "Json", "json"
|
|
44
|
+
["String", null]
|
|
45
|
+
when "Decimal"
|
|
46
|
+
["Float", null]
|
|
47
|
+
when "DateTime", "Datetime"
|
|
48
|
+
["GraphQL::Types::ISO8601DateTime", null]
|
|
49
|
+
when "Date"
|
|
50
|
+
["GraphQL::Types::ISO8601Date", null]
|
|
51
|
+
else
|
|
52
|
+
super
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
def generate_column_string(column)
|
|
59
|
+
name = column.name
|
|
60
|
+
required = column.null ? "" : "!"
|
|
61
|
+
type = column_type_string(column)
|
|
62
|
+
"#{name}:#{required}#{type}"
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def column_type_string(column)
|
|
66
|
+
column.name == "id" ? "ID" : column.type.to_s.camelize
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def class_exists?
|
|
70
|
+
klass.is_a?(Class) && klass.ancestors.include?(ActiveRecord::Base)
|
|
71
|
+
rescue NameError
|
|
72
|
+
false
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def klass
|
|
76
|
+
@klass ||= Module.const_get(type_name.camelize)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# frozen_string_literal: true'
|
|
4
|
+
|
|
5
|
+
require_relative 'resolvers_generator'
|
|
6
|
+
|
|
7
|
+
module Ibrain
|
|
8
|
+
module Graphql
|
|
9
|
+
# TODO: What other options should be supported?
|
|
10
|
+
#
|
|
11
|
+
# @example Generate a `GraphQL::Schema::Resolver` by name
|
|
12
|
+
# rails g graphql:resolver PostsResolver
|
|
13
|
+
class ResolverGenerator < ResolversGenerator
|
|
14
|
+
source_root File.expand_path('templates', __dir__)
|
|
15
|
+
|
|
16
|
+
def create_resolver_file
|
|
17
|
+
if @behavior == :revoke
|
|
18
|
+
log :gsub, "#{options[:directory]}/types/query_type.rb"
|
|
19
|
+
else
|
|
20
|
+
create_resolver_root_type
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
template "resolver.erb", "#{options[:directory]}/resolvers/#{file_name}.rb"
|
|
24
|
+
|
|
25
|
+
sentinel = /class .*QueryType\s*<\s*[^\s]+?\n/m
|
|
26
|
+
in_root do
|
|
27
|
+
gsub_file "#{options[:directory]}/types/query_type.rb", / \# TODO: Add Resolvers as fields\s*\n/m, ""
|
|
28
|
+
inject_into_file "#{options[:directory]}/types/query_type.rb", " field :#{field_name}, resolver: Resolvers::#{resolver_name}\n\n", after: sentinel, verbose: false, force: false
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rails/generators'
|
|
4
|
+
require 'rails/generators/named_base'
|
|
5
|
+
require_relative 'core'
|
|
6
|
+
|
|
7
|
+
module Ibrain
|
|
8
|
+
module Graphql
|
|
9
|
+
# TODO: What other options should be supported?
|
|
10
|
+
#
|
|
11
|
+
# @example Generate a `GraphQL::Schema::Resolver` by name
|
|
12
|
+
# rails g graphql:resolver PostsResolver
|
|
13
|
+
class ResolversGenerator < Rails::Generators::Base
|
|
14
|
+
include Core
|
|
15
|
+
|
|
16
|
+
desc "Create a resolver by name"
|
|
17
|
+
source_root File.expand_path('templates', __dir__)
|
|
18
|
+
|
|
19
|
+
argument :name, type: :string
|
|
20
|
+
class_option :model, type: :string, default: nil
|
|
21
|
+
|
|
22
|
+
def initialize(args, *options) # :nodoc:
|
|
23
|
+
# Unfreeze name in case it's given as a frozen string
|
|
24
|
+
args[0] = args[0].dup if args[0].is_a?(String) && args[0].frozen?
|
|
25
|
+
super
|
|
26
|
+
|
|
27
|
+
assign_names!(name)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
attr_reader :file_name, :resolver_name, :field_name, :model_name
|
|
31
|
+
|
|
32
|
+
def create_resolver_file
|
|
33
|
+
if @behavior == :revoke
|
|
34
|
+
log :gsub, "#{options[:directory]}/types/query_type.rb"
|
|
35
|
+
else
|
|
36
|
+
create_resolver_root_type
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
template "resolvers.erb", "#{options[:directory]}/resolvers/#{file_name}.rb"
|
|
40
|
+
template "aggregate.erb", "#{options[:directory]}/resolvers/#{file_name}_aggregate.rb"
|
|
41
|
+
|
|
42
|
+
sentinel = /class .*QueryType\s*<\s*[^\s]+?\n/m
|
|
43
|
+
in_root do
|
|
44
|
+
gsub_file "#{options[:directory]}/types/query_type.rb", / \# TODO: Add Resolvers as fields\s*\n/m, ""
|
|
45
|
+
inject_into_file "#{options[:directory]}/types/query_type.rb", " field :#{field_name}, resolver: Resolvers::#{resolver_name}\n field :#{field_name}_aggregate, resolver: Resolvers::#{resolver_name}Aggregate\n\n", after: sentinel, verbose: false, force: false
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
def assign_names!(name)
|
|
52
|
+
@field_name = name.camelize.underscore
|
|
53
|
+
@resolver_name = name.camelize(:upper)
|
|
54
|
+
@file_name = name.camelize.underscore
|
|
55
|
+
@model_name = options[:model].blank? ? 'Post' : options[:model].capitalize
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<% module_namespacing_when_supported do -%>
|
|
2
|
+
module Resolvers
|
|
3
|
+
class <%= "#{resolver_name}Aggregate" %> < Ibrain::Resolvers::BaseAggregate
|
|
4
|
+
# define resolve method
|
|
5
|
+
def resolve(args)
|
|
6
|
+
<%= model_name.capitalize %>.ransack(args[:filter]).result
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
<% end -%>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<% module_namespacing_when_supported do -%>
|
|
2
|
+
module Mutations
|
|
3
|
+
class <%= mutation_name %> < Ibrain::Mutations::BaseMutation
|
|
4
|
+
# TODO: define return fields
|
|
5
|
+
field :<%= model_name.underscore %>, Types::<%= model_name %>Type, null: false
|
|
6
|
+
|
|
7
|
+
# TODO: define arguments
|
|
8
|
+
# argument :name, String, required: true
|
|
9
|
+
|
|
10
|
+
# TODO: define resolve method
|
|
11
|
+
def resolve(args)
|
|
12
|
+
# TODO: define logic
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
<% end -%>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<% module_namespacing_when_supported do -%>
|
|
2
|
+
module Types
|
|
3
|
+
module Objects
|
|
4
|
+
class <%= type_ruby_name.split('::')[-1] %> < Ibrain::Types::BaseObject
|
|
5
|
+
implements Ibrain::Interfaces::RecordInterface
|
|
6
|
+
|
|
7
|
+
<% normalized_fields.each do |f| %> <%= f.to_ruby %>
|
|
8
|
+
<% end %>end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
<% end -%>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<% module_namespacing_when_supported do -%>
|
|
2
|
+
module Resolvers
|
|
3
|
+
class <%= resolver_name %> < Ibrain::Resolvers::BaseResolver
|
|
4
|
+
# TODO: define return fields
|
|
5
|
+
type Types::Objects::<%= model_name.capitalize %>Type, null: false
|
|
6
|
+
|
|
7
|
+
argument :id, ID, required: false
|
|
8
|
+
|
|
9
|
+
# TODO: define resolve method
|
|
10
|
+
def resolve(args)
|
|
11
|
+
<%= model_name.capitalize %>.find args[:id]
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
<% end -%>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<% module_namespacing_when_supported do -%>
|
|
2
|
+
module Resolvers
|
|
3
|
+
class <%= resolver_name %> < <%= "#{resolver_name}Aggregate" %>
|
|
4
|
+
# TODO: define return fields
|
|
5
|
+
type [Types::Objects::<%= model_name.capitalize %>Type], null: false
|
|
6
|
+
|
|
7
|
+
# TODO: define resolve method
|
|
8
|
+
def resolve(args)
|
|
9
|
+
super(args).limit(args[:limit]).offset(args[:offset])
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
<% end -%>
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rails/generators'
|
|
4
|
+
require 'rails/generators/base'
|
|
5
|
+
require 'graphql'
|
|
6
|
+
require 'active_support'
|
|
7
|
+
require 'active_support/core_ext/string/inflections'
|
|
8
|
+
require_relative 'core'
|
|
9
|
+
|
|
10
|
+
module Ibrain
|
|
11
|
+
module Graphql
|
|
12
|
+
class TypeGeneratorBase < Rails::Generators::Base
|
|
13
|
+
include Core
|
|
14
|
+
|
|
15
|
+
argument :type_name,
|
|
16
|
+
type: :string,
|
|
17
|
+
banner: "TypeName",
|
|
18
|
+
desc: "Name of this object type (expressed as Ruby or GraphQL)"
|
|
19
|
+
|
|
20
|
+
# Take a type expression in any combination of GraphQL or Ruby styles
|
|
21
|
+
# and return it in a specified output style
|
|
22
|
+
# TODO: nullability / list with `mode: :graphql` doesn't work
|
|
23
|
+
# @param type_expresson [String]
|
|
24
|
+
# @param mode [Symbol]
|
|
25
|
+
# @param null [Boolean]
|
|
26
|
+
# @return [(String, Boolean)] The type expression, followed by `null:` value
|
|
27
|
+
def self.normalize_type_expression(type_expression, mode:, null: true)
|
|
28
|
+
if type_expression.start_with?("!")
|
|
29
|
+
normalize_type_expression(type_expression[1..-1], mode: mode, null: false)
|
|
30
|
+
elsif type_expression.end_with?("!")
|
|
31
|
+
normalize_type_expression(type_expression[0..-2], mode: mode, null: false)
|
|
32
|
+
elsif type_expression.start_with?("[") && type_expression.end_with?("]")
|
|
33
|
+
name, is_null = normalize_type_expression(type_expression[1..-2], mode: mode, null: null)
|
|
34
|
+
["[#{name}]", is_null]
|
|
35
|
+
elsif type_expression.end_with?("Type")
|
|
36
|
+
normalize_type_expression(type_expression[0..-5], mode: mode, null: null)
|
|
37
|
+
elsif type_expression.start_with?("Types::")
|
|
38
|
+
normalize_type_expression(type_expression[7..-1], mode: mode, null: null)
|
|
39
|
+
elsif type_expression.start_with?("types.")
|
|
40
|
+
normalize_type_expression(type_expression[6..-1], mode: mode, null: null)
|
|
41
|
+
else
|
|
42
|
+
case mode
|
|
43
|
+
when :ruby
|
|
44
|
+
case type_expression
|
|
45
|
+
when "Int"
|
|
46
|
+
["Integer", null]
|
|
47
|
+
when "Integer", "Float", "Boolean", "String", "ID"
|
|
48
|
+
[type_expression, null]
|
|
49
|
+
else
|
|
50
|
+
["Types::#{type_expression.camelize}Type", null]
|
|
51
|
+
end
|
|
52
|
+
when :graphql
|
|
53
|
+
[type_expression.camelize, null]
|
|
54
|
+
else
|
|
55
|
+
raise "Unexpected normalize mode: #{mode}"
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
private
|
|
61
|
+
|
|
62
|
+
# @return [String] The user-provided type name, normalized to Ruby code
|
|
63
|
+
def type_ruby_name
|
|
64
|
+
@type_ruby_name ||= self.class.normalize_type_expression(type_name, mode: :ruby)[0]
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# @return [String] The user-provided type name, as a GraphQL name
|
|
68
|
+
def type_graphql_name
|
|
69
|
+
@type_graphql_name ||= self.class.normalize_type_expression(type_name, mode: :graphql)[0]
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# @return [String] The user-provided type name, as a file name (without extension)
|
|
73
|
+
def type_file_name
|
|
74
|
+
@type_file_name ||= "#{type_graphql_name}Type".underscore
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# @return [Array<NormalizedField>] User-provided fields, in `(name, Ruby type name)` pairs
|
|
78
|
+
def normalized_fields
|
|
79
|
+
skip_fields = ["created_at:!Datetime", "updated_at:!Datetime"]
|
|
80
|
+
|
|
81
|
+
@normalized_fields ||= fields.reject { |f| skip_fields.include?(f) }.map { |f|
|
|
82
|
+
name, raw_type = f.split(":", 2)
|
|
83
|
+
type_expr, null = self.class.normalize_type_expression(raw_type, mode: :ruby)
|
|
84
|
+
NormalizedField.new(name, type_expr, null)
|
|
85
|
+
}
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
class NormalizedField
|
|
89
|
+
def initialize(name, type_expr, null)
|
|
90
|
+
@name = name
|
|
91
|
+
@type_expr = type_expr
|
|
92
|
+
@null = null
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def to_ruby
|
|
96
|
+
"field :#{@name}, #{@type_expr}, null: #{@null}"
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rails/generators'
|
|
4
|
+
require 'ibrain/logger'
|
|
5
|
+
|
|
6
|
+
module Ibrain
|
|
7
|
+
# @private
|
|
8
|
+
class InstallGenerator < Rails::Generators::Base
|
|
9
|
+
CORE_MOUNT_ROUTE = "mount Ibrain::Core::Engine"
|
|
10
|
+
source_root File.expand_path('templates', __dir__)
|
|
11
|
+
|
|
12
|
+
class_option :user_class, type: :string
|
|
13
|
+
class_option :with_authentication, type: :boolean, default: true
|
|
14
|
+
class_option :with_rubocop, type: :boolean, default: true
|
|
15
|
+
class_option :with_graphql, type: :boolean, default: false
|
|
16
|
+
class_option :with_annotation, type: :boolean, default: true
|
|
17
|
+
class_option :with_sendgrid, type: :boolean, default: false
|
|
18
|
+
class_option :enforce_available_locales, type: :boolean, default: nil
|
|
19
|
+
class_option :with_ridgepole, type: :boolean, default: true
|
|
20
|
+
|
|
21
|
+
def additional_tweaks
|
|
22
|
+
return unless File.exist? 'public/robots.txt'
|
|
23
|
+
|
|
24
|
+
append_file "public/robots.txt", <<-ROBOTS.strip_heredoc
|
|
25
|
+
User-agent: *
|
|
26
|
+
Disallow: /user
|
|
27
|
+
Disallow: /account
|
|
28
|
+
Disallow: /api
|
|
29
|
+
Disallow: /password
|
|
30
|
+
ROBOTS
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def create_overrides_directory
|
|
34
|
+
empty_directory "app/overrides"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def configure_application
|
|
38
|
+
application <<-RUBY
|
|
39
|
+
# Load application's model / class decorators
|
|
40
|
+
initializer 'ibrain.decorators' do |app|
|
|
41
|
+
config.to_prepare do
|
|
42
|
+
Dir.glob(Rails.root.join('app/**/*_decorator*.rb')) do |path|
|
|
43
|
+
require_dependency(path)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
RUBY
|
|
48
|
+
|
|
49
|
+
if !options[:enforce_available_locales].nil?
|
|
50
|
+
application <<-RUBY
|
|
51
|
+
I18n.enforce_available_locales = #{options[:enforce_available_locales]}
|
|
52
|
+
RUBY
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def plugin_install_preparation
|
|
57
|
+
@plugins_to_be_installed = []
|
|
58
|
+
@plugin_generators_to_run = []
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def install_auth_plugin
|
|
62
|
+
if options[:with_authentication] && (options[:auto_accept] || !no?("
|
|
63
|
+
Ibrain has a default authentication extension that uses Devise.
|
|
64
|
+
You can find more info at https://github.com/john-techfox/ibrain-auth.git.
|
|
65
|
+
|
|
66
|
+
Would you like to install it? (Y/n)"))
|
|
67
|
+
|
|
68
|
+
@plugins_to_be_installed << 'ibrain-auth' unless system('gem list | grep ibrain-auth')
|
|
69
|
+
@plugin_generators_to_run << 'ibrain:auth:install'
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def run_bundle_install_if_needed_by_plugins
|
|
74
|
+
@plugins_to_be_installed.each do |plugin_name|
|
|
75
|
+
gem plugin_name
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
if options[:with_rubocop]
|
|
79
|
+
append_gem('rubocop', '1.23.0', 'development')
|
|
80
|
+
append_gem('rubocop-performance', '1.12.0', 'development')
|
|
81
|
+
append_gem('rubocop-rails', '2.12.4', 'development')
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
if options[:with_graphql]
|
|
85
|
+
append_gem('graphql', '1.12.6')
|
|
86
|
+
append_gem('graphql-batch', '0.4.3')
|
|
87
|
+
append_gem('graphql-guard', '2.0.0')
|
|
88
|
+
append_gem('graphql-rails-generators', '1.1.2', 'development')
|
|
89
|
+
append_gem('graphiql-rails', '1.8.0', 'development')
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
append_gem('annotate', '3.1.1', 'development') if options[:with_annotation]
|
|
93
|
+
append_gem('sendgrid-ruby', '6.6.0') if options[:with_sendgrid]
|
|
94
|
+
|
|
95
|
+
if options[:with_ridgepole]
|
|
96
|
+
append_gem('ridgepole', '1.0.0', 'development')
|
|
97
|
+
else
|
|
98
|
+
remove_gem('ridgepole')
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
bundle_cleanly{ run "bundle install" } if @plugins_to_be_installed.any?
|
|
102
|
+
run "spring stop" if defined?(Spring)
|
|
103
|
+
|
|
104
|
+
@plugin_generators_to_run.each do |plugin_generator_name|
|
|
105
|
+
generate plugin_generator_name.to_s
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def install_routes
|
|
110
|
+
routes_file_path = File.join('config', 'routes.rb')
|
|
111
|
+
unless File.read(routes_file_path).include? CORE_MOUNT_ROUTE
|
|
112
|
+
insert_into_file routes_file_path, after: "Rails.application.routes.draw do\n" do
|
|
113
|
+
<<-RUBY
|
|
114
|
+
# This line mounts Ibrain's routes at the root of your application.
|
|
115
|
+
# This means, any requests to URLs such as /graphql, will go to Ibrain::GraphqlController,
|
|
116
|
+
# any requests to URLS such as /auth, will go to Ibrain::AuthController,
|
|
117
|
+
# If you would like to change where this engine is mounted, simply change the :at option to something different.
|
|
118
|
+
#
|
|
119
|
+
# We ask that you don't use the :as option here, as Ibrain relies on it being the default of "ibrain"
|
|
120
|
+
#{CORE_MOUNT_ROUTE}, at: '/'
|
|
121
|
+
|
|
122
|
+
# Please contact to Tai Nguyen Van <tainv@its-global.vn> if you have any question?
|
|
123
|
+
RUBY
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
unless options[:quiet]
|
|
128
|
+
Ibrain::Logger.info "*" * 50
|
|
129
|
+
Ibrain::Logger.info "We added the following line to your application's config/routes.rb file:"
|
|
130
|
+
Ibrain::Logger.info " "
|
|
131
|
+
Ibrain::Logger.info " #{CORE_MOUNT_ROUTE}, at: '/'"
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def add_files
|
|
136
|
+
template 'config/initializers/ibrain.rb.tt', 'config/initializers/ibrain.rb', { skip: true }
|
|
137
|
+
template 'config/initializers/cors.tt', 'config/initializers/cors.rb', { skip: true }
|
|
138
|
+
template 'config/puma.tt', 'config/puma.rb', { skip: true }
|
|
139
|
+
yml_template 'config/database.tt', 'config/database.yml', { skip: true }
|
|
140
|
+
template '.rubocop.yml.tt', '.rubocop.yml', { skip: true } if options[:with_rubocop]
|
|
141
|
+
|
|
142
|
+
if options[:with_graphql]
|
|
143
|
+
template 'graphql/app_schema.rb.tt', 'app/graphql/app_schema.rb', { skip: true }
|
|
144
|
+
template 'graphql/types/mutation_type.rb.tt', 'app/graphql/types/mutation_type.rb', { skip: true }
|
|
145
|
+
template 'graphql/types/query_type.rb.tt', 'app/graphql/types/query_type.rb', { skip: true }
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def complete
|
|
150
|
+
unless options[:quiet]
|
|
151
|
+
Ibrain::Logger.info "*" * 50
|
|
152
|
+
Ibrain::Logger.info "Ibrain has been installed successfully. You're all ready to go!"
|
|
153
|
+
Ibrain::Logger.info " "
|
|
154
|
+
Ibrain::Logger.info "Enjoy!"
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
private
|
|
159
|
+
|
|
160
|
+
def bundle_cleanly(&block)
|
|
161
|
+
Bundler.respond_to?(:with_unbundled_env) ? Bundler.with_unbundled_env(&block) : Bundler.with_clean_env(&block)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def append_gem(name, version, group_name = nil)
|
|
165
|
+
shell_command = ["\ngem '#{name}', '~> #{version}'"]
|
|
166
|
+
shell_command.push("group: :#{group_name}") if group_name.present?
|
|
167
|
+
string_command = shell_command.join(', ')
|
|
168
|
+
gems = Gem.loaded_specs.values.map(&:full_name).join(' ')
|
|
169
|
+
|
|
170
|
+
system( `echo "#{string_command}" >> Gemfile` ) unless gems.include?("#{name}-")
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def remove_gem(name)
|
|
174
|
+
gems = Gem.loaded_specs.values.map(&:full_name).join(' ')
|
|
175
|
+
|
|
176
|
+
system( "bundle remove #{name}" ) if gems.include?("#{name}-")
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def yml_template(source, *args)
|
|
180
|
+
config = args.last.is_a?(Hash) ? args.pop : {}
|
|
181
|
+
destination = args.first || source.sub(/#{TEMPLATE_EXTNAME}$/o, "")
|
|
182
|
+
source = File.expand_path(find_in_source_paths(source.to_s))
|
|
183
|
+
|
|
184
|
+
create_file destination, nil, config do
|
|
185
|
+
File.read(source)
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
default: &default
|
|
2
|
+
adapter: <%= ENV.fetch("DATABASE_ADAPTER") { 'postgresql' } %>
|
|
3
|
+
encoding: utf8mb4
|
|
4
|
+
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
|
|
5
|
+
host: <%= ENV.fetch('DATABASE_HOSTNAME') { 'localhost' }%>
|
|
6
|
+
username: <%= ENV.fetch('DATABASE_USERNAME') { 'ibrain' }%>
|
|
7
|
+
password: <%= ENV.fetch('DATABASE_PASSWORD') { 'ibrain-password' }%>
|
|
8
|
+
|
|
9
|
+
development:
|
|
10
|
+
<<: *default
|
|
11
|
+
database: <%= ENV.fetch('DATABASE_NAME') { 'ibrain_development' }%>
|
|
12
|
+
|
|
13
|
+
staging:
|
|
14
|
+
<<: *default
|
|
15
|
+
database: <%= ENV.fetch('DATABASE_NAME') { 'ibrain_staging' }%>
|
|
16
|
+
|
|
17
|
+
test:
|
|
18
|
+
<<: *default
|
|
19
|
+
database: <%= ENV.fetch('DATABASE_NAME') { 'ibrain_test' }%>
|
|
20
|
+
|
|
21
|
+
production:
|
|
22
|
+
<<: *default
|
|
23
|
+
database: <%= ENV.fetch('DATABASE_NAME') { 'ibrain_production' }%>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Be sure to restart your server when you modify this file.
|
|
2
|
+
|
|
3
|
+
# Avoid CORS issues when API is called from the frontend app.
|
|
4
|
+
# Handle Cross-Origin Resource Sharing (CORS) in order to accept cross-origin AJAX requests.
|
|
5
|
+
|
|
6
|
+
# Read more: https://github.com/cyu/rack-cors
|
|
7
|
+
|
|
8
|
+
Rails.application.config.middleware.insert_before 0, Rack::Cors do
|
|
9
|
+
allow do
|
|
10
|
+
origins '*'
|
|
11
|
+
|
|
12
|
+
resource '*',
|
|
13
|
+
headers: :any,
|
|
14
|
+
methods: [:get, :post, :put, :patch, :delete, :options, :head],
|
|
15
|
+
expose: %w[
|
|
16
|
+
X-Requested-With
|
|
17
|
+
Content-Type
|
|
18
|
+
Authorization
|
|
19
|
+
Accept
|
|
20
|
+
Accept-Encoding
|
|
21
|
+
Access-Control-Allow-Credentials
|
|
22
|
+
],
|
|
23
|
+
credentials: true
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Ibrain version defaults for preferences that are not overridden
|
|
2
|
+
Ibrain.load_defaults '<%= Ibrain.ibrain_version %>'
|
|
3
|
+
|
|
4
|
+
Ibrain.config do |config|
|
|
5
|
+
# Core:
|
|
6
|
+
# from address for emails
|
|
7
|
+
config.mails_from = "info@example.com"
|
|
8
|
+
|
|
9
|
+
# Uncomment to stop tracking inventory levels in the application
|
|
10
|
+
# config.track_inventory_levels = false
|
|
11
|
+
|
|
12
|
+
# When set, data caches are only invalidated when they fall below or rise
|
|
13
|
+
# above the inventory_cache_threshold that is set. Default is to invalidate cache on
|
|
14
|
+
# any inventory changes.
|
|
15
|
+
# config.inventory_cache_threshold = 3
|
|
16
|
+
|
|
17
|
+
# Defaults
|
|
18
|
+
# Permission Sets:
|
|
19
|
+
|
|
20
|
+
# Uncomment and customize the following line to add custom permission sets
|
|
21
|
+
# to a custom users role:
|
|
22
|
+
# config.roles.assign_permissions :role_name, ['Ibrain::PermissionSets::CustomPermissionSet']
|
|
23
|
+
|
|
24
|
+
# @!attribute [rw] guest_token_cookie_options
|
|
25
|
+
# @return [Hash] Add additional guest_token cookie options here (ie. domain or path)
|
|
26
|
+
# config.guest_token_cookie_options = {}
|
|
27
|
+
|
|
28
|
+
# @!attribute [rw] generate_api_key_for_all_roles
|
|
29
|
+
# @return [Boolean] Allow generating api key automatically for user
|
|
30
|
+
# at role_user creation for all roles. (default: +false+)
|
|
31
|
+
# config.generate_api_key_for_all_roles = false
|
|
32
|
+
|
|
33
|
+
# Graphql Policy Object
|
|
34
|
+
# config.graphql_policy = 'Ibrain::Policies::GraphqlPolicy'
|
|
35
|
+
|
|
36
|
+
# Api version for route config
|
|
37
|
+
# config.api_version = 'v1'
|
|
38
|
+
|
|
39
|
+
# Graphql Schema name
|
|
40
|
+
# config.graphql_schema = 'Ibrain::BaseSchema'
|
|
41
|
+
|
|
42
|
+
# Graphql Encryptor key
|
|
43
|
+
# config.ibrain_encryptor_key = Rails.application.secrets.secret_key_base.byteslice(0..31)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
<% if defined?(Ibrain::Api::Engine) -%>
|
|
47
|
+
Ibrain::Api::Config.configure do |config|
|
|
48
|
+
# Localization
|
|
49
|
+
config.locale = 'en'
|
|
50
|
+
|
|
51
|
+
config.requires_authentication = true
|
|
52
|
+
end
|
|
53
|
+
<% end -%>
|
|
54
|
+
|
|
55
|
+
Ibrain.user_class = <%= (options[:user_class].blank? ? "Ibrain::LegacyUser" : options[:user_class]).inspect %>
|