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,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ibrain
|
|
4
|
+
module Types
|
|
5
|
+
class BaseObject < GraphQL::Schema::Object
|
|
6
|
+
implements GraphQL::Relay::Node.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,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ibrain
|
|
4
|
+
module Types
|
|
5
|
+
class BaseQueryType < Types::BaseObject
|
|
6
|
+
# Add `node(id: ID!) and `nodes(ids: [ID!]!)`
|
|
7
|
+
include GraphQL::Types::Relay::HasNodeField
|
|
8
|
+
include GraphQL::Types::Relay::HasNodesField
|
|
9
|
+
|
|
10
|
+
# Add root-level fields here.
|
|
11
|
+
# They will be entry points for queries on your schema.
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
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
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Implementation class for Cancan gem. Instead of overriding this class, consider adding new permissions
|
|
4
|
+
# using the special +register_ability+ method which allows extensions to add their own abilities.
|
|
5
|
+
#
|
|
6
|
+
# See http://github.com/ryanb/cancan for more details on cancan.
|
|
7
|
+
require 'cancan'
|
|
8
|
+
module Ibrain
|
|
9
|
+
class Ability
|
|
10
|
+
include CanCan::Ability
|
|
11
|
+
|
|
12
|
+
class_attribute :abilities
|
|
13
|
+
self.abilities = Set.new
|
|
14
|
+
|
|
15
|
+
attr_reader :user
|
|
16
|
+
|
|
17
|
+
# Allows us to go beyond the standard cancan initialize method which makes it difficult for engines to
|
|
18
|
+
# modify the default +Ability+ of an application. The +ability+ argument must be a class that includes
|
|
19
|
+
# the +CanCan::Ability+ module. The registered ability should behave properly as a stand-alone class
|
|
20
|
+
# and therefore should be easy to test in isolation.
|
|
21
|
+
def self.register_ability(ability)
|
|
22
|
+
abilities.add(ability)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.remove_ability(ability)
|
|
26
|
+
abilities.delete(ability)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def initialize(current_user)
|
|
30
|
+
@user = current_user || Ibrain.user_class.new
|
|
31
|
+
|
|
32
|
+
activate_permission_sets
|
|
33
|
+
register_extension_abilities
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
# Before, this was the only way to extend this ability. Permission sets have been added since.
|
|
39
|
+
# It is recommended to use them instead for extension purposes if possible.
|
|
40
|
+
def register_extension_abilities
|
|
41
|
+
Ability.abilities.each do |clazz|
|
|
42
|
+
ability = clazz.send(:new, user)
|
|
43
|
+
merge(ability)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def activate_permission_sets
|
|
48
|
+
Ibrain::Config.roles.activate_permissions! self, user
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Ibrain::Base < Ibrain::ApplicationRecord
|
|
4
|
+
include ActionView::Helpers::DateHelper
|
|
5
|
+
|
|
6
|
+
self.abstract_class = true
|
|
7
|
+
|
|
8
|
+
def self.adjust_date_for_cdt(datetime)
|
|
9
|
+
datetime.in_time_zone('UTC')
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def string_id
|
|
13
|
+
try(:id).try(:to_s)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
scope :graphql_ransack, lambda { |params|
|
|
17
|
+
ransack(params).result(distinct: true)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
scope :reverse_scope, lambda {
|
|
21
|
+
order(created_at: :desc)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
scope :ransack_query, lambda { |params, page, per_page = 10|
|
|
25
|
+
ransack(params).
|
|
26
|
+
result.
|
|
27
|
+
page(page).
|
|
28
|
+
per(per_page)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
def cryptor
|
|
32
|
+
::Ibrain::Encryptor.new
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def created_in_word
|
|
36
|
+
time_ago_in_words(created_at)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Provides a scope that should be included any time data
|
|
40
|
+
# are fetched with the intention of displaying to the user.
|
|
41
|
+
#
|
|
42
|
+
# Allows individual stores to include any active record scopes or joins
|
|
43
|
+
# when data are displayed.
|
|
44
|
+
def self.display_includes
|
|
45
|
+
where(nil)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ibrain::RansackableAttributes
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
included do
|
|
6
|
+
class_attribute :whitelisted_ransackable_associations
|
|
7
|
+
class_attribute :whitelisted_ransackable_attributes
|
|
8
|
+
|
|
9
|
+
class_attribute :default_ransackable_attributes
|
|
10
|
+
self.default_ransackable_attributes = %w[id]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
class_methods do
|
|
14
|
+
def ransackable_associations(*_args)
|
|
15
|
+
whitelisted_ransackable_associations || []
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def ransackable_attributes(*_args)
|
|
19
|
+
default_ransackable_attributes | (whitelisted_ransackable_attributes || [])
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'discard'
|
|
4
|
+
|
|
5
|
+
module Ibrain
|
|
6
|
+
module SoftDeletable
|
|
7
|
+
extend ActiveSupport::Concern
|
|
8
|
+
|
|
9
|
+
included do
|
|
10
|
+
include Discard::Model
|
|
11
|
+
self.discard_column = :deleted_at
|
|
12
|
+
|
|
13
|
+
default_scope { kept }
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ibrain
|
|
4
|
+
module UserApiAuthentication
|
|
5
|
+
def generate_ibrain_api_key!
|
|
6
|
+
generate_ibrain_api_key
|
|
7
|
+
save!
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def generate_ibrain_api_key
|
|
11
|
+
self.ibrain_api_key = SecureRandom.hex(24)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def clear_ibrain_api_key!
|
|
15
|
+
clear_ibrain_api_key
|
|
16
|
+
save!
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def clear_ibrain_api_key
|
|
20
|
+
self.ibrain_api_key = nil
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ibrain
|
|
4
|
+
module UserMethods
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
|
|
7
|
+
include Ibrain::UserApiAuthentication
|
|
8
|
+
include Ibrain::UserReporting
|
|
9
|
+
|
|
10
|
+
included do
|
|
11
|
+
extend Ibrain::DisplayMoney
|
|
12
|
+
after_create :auto_generate_ibrain_api_key
|
|
13
|
+
|
|
14
|
+
include Ibrain::RansackableAttributes unless included_modules.include?(Ibrain::RansackableAttributes)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def auto_generate_ibrain_api_key
|
|
18
|
+
return if !respond_to?(:ibrain_api_key) || ibrain_api_key.present?
|
|
19
|
+
|
|
20
|
+
if Ibrain::Config.generate_api_key_for_all_roles || (ibrain_roles.map(&:name) & Ibrain::Config.roles_for_auto_api_key).any?
|
|
21
|
+
generate_ibrain_api_key!
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ibrain
|
|
4
|
+
# Default implementation of User.
|
|
5
|
+
#
|
|
6
|
+
# @note This class is intended to be modified by extensions (ex.
|
|
7
|
+
# ibrain-auth)
|
|
8
|
+
class LegacyUser < Ibrain::Base
|
|
9
|
+
include UserMethods
|
|
10
|
+
|
|
11
|
+
self.table_name = 'ibrain_users'
|
|
12
|
+
|
|
13
|
+
def self.model_name
|
|
14
|
+
ActiveModel::Name.new Ibrain::LegacyUser, Ibrain, 'user'
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
attr_accessor :password, :password_confirmation
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ibrain
|
|
4
|
+
class Role < Ibrain::Base
|
|
5
|
+
has_many :role_users, class_name: "Ibrain::RoleUser", dependent: :destroy
|
|
6
|
+
has_many :users, through: :role_users
|
|
7
|
+
|
|
8
|
+
validates :name, uniqueness: { case_sensitive: true }
|
|
9
|
+
|
|
10
|
+
def admin?
|
|
11
|
+
name == "admin"
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ibrain
|
|
4
|
+
class RoleUser < Ibrain::Base
|
|
5
|
+
belongs_to :role, class_name: "Ibrain::Role", optional: true
|
|
6
|
+
belongs_to :user, class_name: Ibrain::UserClassHandle.new, optional: true
|
|
7
|
+
|
|
8
|
+
after_create :auto_generate_ibrain_api_key
|
|
9
|
+
|
|
10
|
+
validates :role_id, uniqueness: { scope: :user_id }
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def auto_generate_ibrain_api_key
|
|
15
|
+
user.try(:auto_generate_ibrain_api_key)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# FriendlyId Global Configuration
|
|
4
|
+
#
|
|
5
|
+
# Use this to set up shared configuration options for your entire application.
|
|
6
|
+
# Any of the configuration options shown here can also be applied to single
|
|
7
|
+
# models by passing arguments to the `friendly_id` class method or defining
|
|
8
|
+
# methods in your model.
|
|
9
|
+
#
|
|
10
|
+
# To learn more, check out the guide:
|
|
11
|
+
#
|
|
12
|
+
# http://norman.github.io/friendly_id/file.Guide.html
|
|
13
|
+
|
|
14
|
+
FriendlyId.defaults do |config|
|
|
15
|
+
# ## Reserved Words
|
|
16
|
+
#
|
|
17
|
+
# Some words could conflict with Rails's routes when used as slugs, or are
|
|
18
|
+
# undesirable to allow as slugs. Edit this list as needed for your app.
|
|
19
|
+
config.use :reserved
|
|
20
|
+
|
|
21
|
+
# ## Friendly Finders
|
|
22
|
+
#
|
|
23
|
+
# Uncomment this to use friendly finders in all models. By default, if
|
|
24
|
+
# you wish to find a record by its friendly id, you must do:
|
|
25
|
+
#
|
|
26
|
+
# MyModel.friendly.find('foo')
|
|
27
|
+
#
|
|
28
|
+
# If you uncomment this, you can do:
|
|
29
|
+
#
|
|
30
|
+
# MyModel.find('foo')
|
|
31
|
+
#
|
|
32
|
+
# This is significantly more convenient but may not be appropriate for
|
|
33
|
+
# all applications, so you must explicity opt-in to this behavior. You can
|
|
34
|
+
# always also configure it on a per-model basis if you prefer.
|
|
35
|
+
#
|
|
36
|
+
# Something else to consider is that using the :finders addon boosts
|
|
37
|
+
# performance because it will avoid Rails-internal code that makes runtime
|
|
38
|
+
# calls to `Module.extend`.
|
|
39
|
+
#
|
|
40
|
+
# config.use :finders
|
|
41
|
+
#
|
|
42
|
+
# ## Slugs
|
|
43
|
+
#
|
|
44
|
+
# Most applications will use the :slugged module everywhere. If you wish
|
|
45
|
+
# to do so, uncomment the following line.
|
|
46
|
+
#
|
|
47
|
+
# config.use :slugged
|
|
48
|
+
#
|
|
49
|
+
# By default, FriendlyId's :slugged addon expects the slug column to be named
|
|
50
|
+
# 'slug', but you can change it if you wish.
|
|
51
|
+
#
|
|
52
|
+
# config.slug_column = 'slug'
|
|
53
|
+
#
|
|
54
|
+
# When FriendlyId can not generate a unique ID from your base method, it appends
|
|
55
|
+
# a UUID, separated by a single dash. You can configure the character used as the
|
|
56
|
+
# separator. If you're upgrading from FriendlyId 4, you may wish to replace this
|
|
57
|
+
# with two dashes.
|
|
58
|
+
#
|
|
59
|
+
# config.sequence_separator = '-'
|
|
60
|
+
#
|
|
61
|
+
# ## Tips and Tricks
|
|
62
|
+
#
|
|
63
|
+
# ### Controlling when slugs are generated
|
|
64
|
+
#
|
|
65
|
+
# As of FriendlyId 5.0, new slugs are generated only when the slug field is
|
|
66
|
+
# nil, but if you're using a column as your base method can change this
|
|
67
|
+
# behavior by overriding the `should_generate_new_friendly_id` method that
|
|
68
|
+
# FriendlyId adds to your model. The change below makes FriendlyId 5.0 behave
|
|
69
|
+
# more like 4.0.
|
|
70
|
+
#
|
|
71
|
+
# config.use Module.new {
|
|
72
|
+
# def should_generate_new_friendly_id?
|
|
73
|
+
# slug.blank? || <your_column_name_here>_changed?
|
|
74
|
+
# end
|
|
75
|
+
# }
|
|
76
|
+
#
|
|
77
|
+
# FriendlyId uses Rails's `parameterize` method to generate slugs, but for
|
|
78
|
+
# languages that don't use the Roman alphabet, that's not usually suffient. Here
|
|
79
|
+
# we use the Babosa library to transliterate Russian Cyrillic slugs to ASCII. If
|
|
80
|
+
# you use this, don't forget to add "babosa" to your Gemfile.
|
|
81
|
+
#
|
|
82
|
+
# config.use Module.new {
|
|
83
|
+
# def normalize_friendly_id(text)
|
|
84
|
+
# text.to_slug.normalize! transliterations: [:russian, :latin]
|
|
85
|
+
# end
|
|
86
|
+
# }
|
|
87
|
+
end
|
data/config/routes.rb
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
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
|
|
9
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rails/generators/base'
|
|
4
|
+
|
|
5
|
+
module Ibrain
|
|
6
|
+
module Graphql
|
|
7
|
+
module Core
|
|
8
|
+
def self.included(base)
|
|
9
|
+
base.send(
|
|
10
|
+
:class_option,
|
|
11
|
+
:directory,
|
|
12
|
+
type: :string,
|
|
13
|
+
default: "app/graphql",
|
|
14
|
+
desc: "Directory where generated files should be saved"
|
|
15
|
+
)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def insert_root_type(type, name)
|
|
19
|
+
log :add_root_type, type
|
|
20
|
+
sentinel = /< GraphQL::Schema\s*\n/m
|
|
21
|
+
|
|
22
|
+
in_root do
|
|
23
|
+
if File.exist?(schema_file_path)
|
|
24
|
+
inject_into_file schema_file_path, " #{type}(Types::#{name})\n", after: sentinel, verbose: false, force: false
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def create_mutation_root_type
|
|
30
|
+
create_dir("#{options[:directory]}/mutations")
|
|
31
|
+
insert_root_type('mutation', 'MutationType')
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def create_resolver_root_type
|
|
35
|
+
create_dir("#{options[:directory]}/resolvers")
|
|
36
|
+
insert_root_type('query', 'QueryType')
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def schema_file_path
|
|
40
|
+
"#{options[:directory]}/#{schema_name.underscore}.rb"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def create_dir(dir)
|
|
44
|
+
empty_directory(dir)
|
|
45
|
+
if !options[:skip_keeps]
|
|
46
|
+
create_file("#{dir}/.keep")
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def module_namespacing_when_supported(&block)
|
|
51
|
+
if defined?(module_namespacing)
|
|
52
|
+
module_namespacing(&block)
|
|
53
|
+
else
|
|
54
|
+
yield
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
private
|
|
59
|
+
|
|
60
|
+
def schema_name
|
|
61
|
+
@schema_name ||= options[:schema] || "#{parent_name}Schema"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def parent_name
|
|
65
|
+
require File.expand_path("config/application", destination_root)
|
|
66
|
+
|
|
67
|
+
if Rails.application.class.respond_to?(:module_parent_name)
|
|
68
|
+
Rails.application.class.module_parent_name
|
|
69
|
+
else
|
|
70
|
+
Rails.application.class.parent_name
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
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::RelayClassicMutation` by name
|
|
12
|
+
# rails g graphql:mutation CreatePostMutation
|
|
13
|
+
class MutationGenerator < Rails::Generators::Base
|
|
14
|
+
include Core
|
|
15
|
+
|
|
16
|
+
desc "Create a Relay Classic mutation 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, :mutation_name, :field_name, :model_name
|
|
31
|
+
|
|
32
|
+
def create_mutation_file
|
|
33
|
+
if @behavior == :revoke
|
|
34
|
+
log :gsub, "#{options[:directory]}/types/mutation_type.rb"
|
|
35
|
+
else
|
|
36
|
+
create_mutation_root_type
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
template "mutation.erb", "#{options[:directory]}/mutations/#{file_name}.rb"
|
|
40
|
+
|
|
41
|
+
sentinel = /class .*MutationType\s*<\s*[^\s]+?\n/m
|
|
42
|
+
in_root do
|
|
43
|
+
gsub_file "#{options[:directory]}/types/mutation_type.rb", / \# TODO: Add Mutations as fields\s*\n/m, ""
|
|
44
|
+
inject_into_file "#{options[:directory]}/types/mutation_type.rb", " field :#{field_name}, mutation: Mutations::#{mutation_name}\n", after: sentinel, verbose: false, force: false
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def assign_names!(name)
|
|
51
|
+
@field_name = name.camelize.underscore
|
|
52
|
+
@mutation_name = name.camelize(:upper)
|
|
53
|
+
@file_name = name.camelize.underscore
|
|
54
|
+
@model_name = options[:model].blank? ? 'Post' : options[:model].capitalize
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|