rhino_project_core 0.20.0.alpha.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (134) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +28 -0
  4. data/Rakefile +35 -0
  5. data/app/assets/stripe_flow.png +0 -0
  6. data/app/controllers/concerns/rhino/authenticated.rb +18 -0
  7. data/app/controllers/concerns/rhino/error_handling.rb +60 -0
  8. data/app/controllers/concerns/rhino/paper_trail_whodunnit.rb +11 -0
  9. data/app/controllers/concerns/rhino/permit.rb +38 -0
  10. data/app/controllers/concerns/rhino/set_current_user.rb +13 -0
  11. data/app/controllers/rhino/account_controller.rb +34 -0
  12. data/app/controllers/rhino/active_model_extension_controller.rb +52 -0
  13. data/app/controllers/rhino/base_controller.rb +23 -0
  14. data/app/controllers/rhino/crud_controller.rb +57 -0
  15. data/app/controllers/rhino/simple_controller.rb +13 -0
  16. data/app/controllers/rhino/simple_stream_controller.rb +12 -0
  17. data/app/helpers/rhino/omniauth_helper.rb +67 -0
  18. data/app/helpers/rhino/policy_helper.rb +42 -0
  19. data/app/helpers/rhino/segment_helper.rb +62 -0
  20. data/app/models/rhino/account.rb +13 -0
  21. data/app/models/rhino/current.rb +7 -0
  22. data/app/models/rhino/user.rb +44 -0
  23. data/app/overrides/active_record/autosave_association_override.rb +18 -0
  24. data/app/overrides/active_record/delegated_type_override.rb +14 -0
  25. data/app/overrides/activestorage/direct_uploads_controller_override.rb +23 -0
  26. data/app/overrides/activestorage/redirect_controller_override.rb +21 -0
  27. data/app/overrides/activestorage/redirect_representation_controller_override.rb +21 -0
  28. data/app/overrides/devise_token_auth/confirmations_controller_override.rb +14 -0
  29. data/app/overrides/devise_token_auth/omniauth_callbacks_controller_override.rb +45 -0
  30. data/app/overrides/devise_token_auth/passwords_controller_override.rb +9 -0
  31. data/app/overrides/devise_token_auth/registrations_controller_override.rb +20 -0
  32. data/app/overrides/devise_token_auth/sessions_controller_override.rb +26 -0
  33. data/app/overrides/devise_token_auth/token_validations_controller_override.rb +18 -0
  34. data/app/policies/rhino/account_policy.rb +27 -0
  35. data/app/policies/rhino/active_storage_attachment_policy.rb +16 -0
  36. data/app/policies/rhino/admin_policy.rb +20 -0
  37. data/app/policies/rhino/base_policy.rb +72 -0
  38. data/app/policies/rhino/crud_policy.rb +109 -0
  39. data/app/policies/rhino/editor_policy.rb +12 -0
  40. data/app/policies/rhino/global_policy.rb +8 -0
  41. data/app/policies/rhino/resource_info_policy.rb +9 -0
  42. data/app/policies/rhino/user_policy.rb +20 -0
  43. data/app/policies/rhino/viewer_policy.rb +19 -0
  44. data/app/resources/rhino/info_graph.rb +41 -0
  45. data/app/resources/rhino/open_api_info.rb +108 -0
  46. data/config/routes.rb +19 -0
  47. data/db/migrate/20180101000000_devise_token_auth_create_users.rb +54 -0
  48. data/db/migrate/20180622142754_add_allow_change_password_to_users.rb +5 -0
  49. data/db/migrate/20191217010224_add_approved_to_users.rb +7 -0
  50. data/db/migrate/20200503182019_change_tokens_to_json_b.rb +9 -0
  51. data/lib/commands/rhino/module/coverage_command.rb +44 -0
  52. data/lib/commands/rhino/module/dummy_command.rb +43 -0
  53. data/lib/commands/rhino/module/new_command.rb +34 -0
  54. data/lib/commands/rhino/module/rails_command.rb +43 -0
  55. data/lib/commands/rhino/module/test_command.rb +43 -0
  56. data/lib/generators/rhino/dev/setup/setup_generator.rb +199 -0
  57. data/lib/generators/rhino/dev/setup/templates/env.client.tt +4 -0
  58. data/lib/generators/rhino/dev/setup/templates/env.root.tt +1 -0
  59. data/lib/generators/rhino/dev/setup/templates/env.server.tt +35 -0
  60. data/lib/generators/rhino/dev/setup/templates/prepare-commit-msg +17 -0
  61. data/lib/generators/rhino/install/install_generator.rb +24 -0
  62. data/lib/generators/rhino/install/templates/account.rb +4 -0
  63. data/lib/generators/rhino/install/templates/rhino.rb +24 -0
  64. data/lib/generators/rhino/install/templates/user.rb +4 -0
  65. data/lib/generators/rhino/model/model_generator.rb +96 -0
  66. data/lib/generators/rhino/module/USAGE +6 -0
  67. data/lib/generators/rhino/module/module_generator.rb +92 -0
  68. data/lib/generators/rhino/module/templates/%name%.gemspec.tt +24 -0
  69. data/lib/generators/rhino/module/templates/lib/%namespaced_name%/engine.rb.tt +18 -0
  70. data/lib/generators/rhino/module/templates/lib/generators/%namespaced_name%/install/install_generator.rb.tt +12 -0
  71. data/lib/generators/rhino/module/templates/lib/tasks/%namespaced_name%_tasks.rake.tt +13 -0
  72. data/lib/generators/rhino/module/templates/test/dummy/app/models/user.rb +4 -0
  73. data/lib/generators/rhino/module/templates/test/dummy/config/database.yml +25 -0
  74. data/lib/generators/rhino/module/templates/test/dummy/config/initializers/devise.rb +311 -0
  75. data/lib/generators/rhino/module/templates/test/dummy/config/initializers/devise_token_auth.rb +71 -0
  76. data/lib/generators/rhino/module/templates/test/test_helper.rb +54 -0
  77. data/lib/generators/rhino/policy/policy_generator.rb +33 -0
  78. data/lib/generators/rhino/policy/templates/policy.rb.tt +46 -0
  79. data/lib/generators/test_unit/rhino_policy_generator.rb +13 -0
  80. data/lib/generators/test_unit/templates/policy_test.rb.tt +57 -0
  81. data/lib/rhino/engine.rb +166 -0
  82. data/lib/rhino/omniauth/strategies/azure_o_auth2.rb +16 -0
  83. data/lib/rhino/resource/active_model_extension/backing_store/google_sheet.rb +89 -0
  84. data/lib/rhino/resource/active_model_extension/backing_store.rb +33 -0
  85. data/lib/rhino/resource/active_model_extension/describe.rb +38 -0
  86. data/lib/rhino/resource/active_model_extension/params.rb +70 -0
  87. data/lib/rhino/resource/active_model_extension/properties.rb +231 -0
  88. data/lib/rhino/resource/active_model_extension/reference.rb +50 -0
  89. data/lib/rhino/resource/active_model_extension/routing.rb +15 -0
  90. data/lib/rhino/resource/active_model_extension/serialization.rb +16 -0
  91. data/lib/rhino/resource/active_model_extension.rb +38 -0
  92. data/lib/rhino/resource/active_record_extension/describe.rb +44 -0
  93. data/lib/rhino/resource/active_record_extension/params.rb +213 -0
  94. data/lib/rhino/resource/active_record_extension/properties.rb +85 -0
  95. data/lib/rhino/resource/active_record_extension/properties_describe.rb +228 -0
  96. data/lib/rhino/resource/active_record_extension/reference.rb +50 -0
  97. data/lib/rhino/resource/active_record_extension/routing.rb +21 -0
  98. data/lib/rhino/resource/active_record_extension/search.rb +23 -0
  99. data/lib/rhino/resource/active_record_extension/serialization.rb +16 -0
  100. data/lib/rhino/resource/active_record_extension/super_admin.rb +25 -0
  101. data/lib/rhino/resource/active_record_extension.rb +32 -0
  102. data/lib/rhino/resource/active_record_tree.rb +50 -0
  103. data/lib/rhino/resource/active_storage_extension.rb +41 -0
  104. data/lib/rhino/resource/describe.rb +19 -0
  105. data/lib/rhino/resource/owner.rb +172 -0
  106. data/lib/rhino/resource/params.rb +31 -0
  107. data/lib/rhino/resource/properties.rb +192 -0
  108. data/lib/rhino/resource/reference.rb +29 -0
  109. data/lib/rhino/resource/routing.rb +107 -0
  110. data/lib/rhino/resource/serialization.rb +13 -0
  111. data/lib/rhino/resource/sieves.rb +36 -0
  112. data/lib/rhino/resource.rb +55 -0
  113. data/lib/rhino/sieve/filter.rb +149 -0
  114. data/lib/rhino/sieve/geospatial.rb +45 -0
  115. data/lib/rhino/sieve/helpers.rb +11 -0
  116. data/lib/rhino/sieve/limit.rb +20 -0
  117. data/lib/rhino/sieve/offset.rb +16 -0
  118. data/lib/rhino/sieve/order.rb +143 -0
  119. data/lib/rhino/sieve/search.rb +20 -0
  120. data/lib/rhino/sieve.rb +159 -0
  121. data/lib/rhino/test_case/controller.rb +145 -0
  122. data/lib/rhino/test_case/model.rb +86 -0
  123. data/lib/rhino/test_case/override.rb +19 -0
  124. data/lib/rhino/test_case/policy.rb +76 -0
  125. data/lib/rhino/test_case.rb +11 -0
  126. data/lib/rhino/version.rb +17 -0
  127. data/lib/rhino_project_core.rb +131 -0
  128. data/lib/tasks/rhino.rake +24 -0
  129. data/lib/tasks/rhino_dev.rake +17 -0
  130. data/lib/validators/country_validator.rb +11 -0
  131. data/lib/validators/email_validator.rb +8 -0
  132. data/lib/validators/ipv4_validator.rb +10 -0
  133. data/lib/validators/mac_address_validator.rb +9 -0
  134. metadata +531 -0
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rhino
4
+ class OpenApiInfo
5
+ include Rhino::Resource
6
+
7
+ rhino_owner_global
8
+
9
+ rhino_routing only: [:index], path: 'info/openapi'
10
+ rhino_controller :simple
11
+ rhino_policy :resource_info
12
+
13
+ def self.describe
14
+ nil
15
+ end
16
+
17
+ def self.index
18
+ JSON.pretty_generate({
19
+ openapi: '3.0.3',
20
+ components: {
21
+ schemas: describe_schemas
22
+ },
23
+ paths: describe_paths,
24
+ info: describe_info
25
+ })
26
+ end
27
+
28
+ def self.describe_schemas
29
+ Rhino.resource_classes.index_with(&:describe).compact.transform_keys { |r| r.model_name.singular }
30
+ end
31
+
32
+ def self.describe_parameter(param)
33
+ {
34
+ name: param,
35
+ in: "path",
36
+ required: true
37
+ }
38
+ end
39
+
40
+ # https://gist.github.com/bantic/5688232#gistcomment-3274704
41
+ RESPONSE_CODES = [200, 400, 403, 422].freeze
42
+ SUCCESS_CODES = [200].freeze
43
+ def self.describe_path_content(klass, code)
44
+ {
45
+ "application/json":
46
+ ({ schema: { "$ref": "#/components/schemas/#{klass.model_name.singular}" } } if SUCCESS_CODES.include?(code)) || {}
47
+ }
48
+ end
49
+
50
+ def self.describe_path_responses(klass)
51
+ RESPONSE_CODES.index_with do |code|
52
+ {
53
+ description: Rack::Utils::HTTP_STATUS_CODES[code],
54
+ content: describe_path_content(klass, code)
55
+ }
56
+ end
57
+ end
58
+
59
+ def self.describe_path(path) # rubocop:todo Metrics/AbcSize
60
+ new_path = path.index_by { |p| p[:verb].downcase.to_sym }
61
+ new_path.transform_values! do |verb_values|
62
+ klass = verb_values[:rhino_resource].constantize
63
+
64
+ verb_info = {
65
+ operationId: "#{klass.model_name.singular}-#{verb_values[:action]}",
66
+ parameters: verb_values[:required_names].map { |param| describe_parameter(param) },
67
+ responses: describe_path_responses(klass),
68
+ tags: [klass.model_name.singular]
69
+ }
70
+
71
+ verb_info
72
+ end
73
+
74
+ new_path
75
+ end
76
+
77
+ PATH_IGNORES = ["Rhino::OpenApiInfo", "Rhino::InfoGraph"].freeze
78
+ def self.describe_paths # rubocop:todo Metrics/AbcSize
79
+ routes = Rails.application.routes.routes
80
+
81
+ # Extract the path information we need
82
+ paths = routes.map { |r| r.defaults.merge(verb: r.verb, path: r.path.spec.to_s, required_names: r.path.required_names) }
83
+ paths = paths.group_by { |r| r[:path] }
84
+
85
+ # Get rid of non-rhino paths
86
+ # Rhino paths have rhino_resource set as an attribute when the routes are created
87
+ paths.transform_values! { |v| v.select { |p| p[:rhino_resource].present? && PATH_IGNORES.exclude?(p[:rhino_resource]) } }
88
+
89
+ # Remove empty hashes
90
+ paths.compact_blank!
91
+
92
+ # For each path, list the verbs it supports
93
+ paths.transform_values! do |path|
94
+ describe_path(path)
95
+ end
96
+ end
97
+
98
+ def self.describe_info
99
+ {
100
+ title: "#{Rails.application.class.module_parent_name} API",
101
+ version: '0.0.0',
102
+ "x-rhino": {
103
+ modules: Rhino.registered_modules
104
+ }
105
+ }
106
+ end
107
+ end
108
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ Rails.application.routes.draw do
4
+ scope Rhino.namespace do
5
+ mount_devise_token_auth_for 'User', at: "auth"
6
+
7
+ Rhino.resource_classes.each do |m|
8
+ if m.route_singular?
9
+ resource m.route_key, path: m.route_path, controller: m.controller_name, only: m.routes, rhino_resource: m.name, format: false
10
+ else
11
+ resources m.route_key, path: m.route_path, controller: m.controller_name, only: m.routes, rhino_resource: m.name, format: false
12
+ end
13
+ end
14
+ end
15
+
16
+ match "*#{Rhino.namespace}", to: 'rhino/base#not_found', via: :all, constraints: lambda { |request|
17
+ request.url[/\/rails\/active_storage\//].nil?
18
+ }
19
+ end
@@ -0,0 +1,54 @@
1
+ class DeviseTokenAuthCreateUsers < ActiveRecord::Migration[5.1]
2
+ def change
3
+ create_table(:users) do |t|
4
+ ## Required
5
+ t.string :provider, :null => false, :default => "email"
6
+ t.string :uid, :null => false, :default => ""
7
+
8
+ ## Database authenticatable
9
+ t.string :encrypted_password, :null => false, :default => ""
10
+
11
+ ## Recoverable
12
+ t.string :reset_password_token
13
+ t.datetime :reset_password_sent_at
14
+
15
+ ## Rememberable
16
+ t.datetime :remember_created_at
17
+
18
+ ## Trackable
19
+ t.integer :sign_in_count, :default => 0, :null => false
20
+ t.datetime :current_sign_in_at
21
+ t.datetime :last_sign_in_at
22
+ t.string :current_sign_in_ip
23
+ t.string :last_sign_in_ip
24
+
25
+ ## Confirmable
26
+ t.string :confirmation_token
27
+ t.datetime :confirmed_at
28
+ t.datetime :confirmation_sent_at
29
+ t.string :unconfirmed_email # Only if using reconfirmable
30
+
31
+ ## Lockable
32
+ # t.integer :failed_attempts, :default => 0, :null => false # Only if lock strategy is :failed_attempts
33
+ # t.string :unlock_token # Only if unlock strategy is :email or :both
34
+ # t.datetime :locked_at
35
+
36
+ ## User Info
37
+ t.string :name
38
+ t.string :nickname
39
+ t.string :image
40
+ t.string :email
41
+
42
+ ## Tokens
43
+ t.json :tokens
44
+
45
+ t.timestamps
46
+ end
47
+
48
+ add_index :users, :email, unique: true
49
+ add_index :users, [:uid, :provider], unique: true
50
+ add_index :users, :reset_password_token, unique: true
51
+ add_index :users, :confirmation_token, unique: true
52
+ # add_index :users, :unlock_token, unique: true
53
+ end
54
+ end
@@ -0,0 +1,5 @@
1
+ class AddAllowChangePasswordToUsers < ActiveRecord::Migration[5.2]
2
+ def change
3
+ add_column :users, :allow_password_change, :boolean, default: false, null: false
4
+ end
5
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AddApprovedToUsers < ActiveRecord::Migration[5.2]
4
+ def change
5
+ add_column :users, :approved, :boolean, default: false
6
+ end
7
+ end
@@ -0,0 +1,9 @@
1
+ class ChangeTokensToJsonB < ActiveRecord::Migration[5.2]
2
+ def up
3
+ change_column :users, :tokens, 'jsonb using tokens::jsonb'
4
+ end
5
+
6
+ def down
7
+ change_column :users, :tokens, 'json using tokens::json'
8
+ end
9
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dotenv"
4
+ require "rails/command"
5
+
6
+ module Rails
7
+ module Command
8
+ module Rhino
9
+ module Module
10
+ class CoverageCommand < Base # :nodoc:
11
+ include Thor::Actions
12
+
13
+ def perform(*args)
14
+ ENV["COVERAGE"] = "1"
15
+ test(*args)
16
+ end
17
+
18
+ protected
19
+ def rhino_command(extra_path, base_command, *args) # rubocop:todo Metrics/MethodLength
20
+ module_name = if Dir.exist?(args[0])
21
+ args.shift
22
+ else
23
+ abort "No module specified"
24
+ end
25
+ module_path = [module_name, extra_path].compact.join("/")
26
+ db_name = "#{module_name}_dummy"
27
+ gem_file_path = File.join(Dir.pwd, "Gemfile")
28
+
29
+ # Getting existing variables and re-use
30
+ ::Dotenv.load
31
+
32
+ inside(module_path) do
33
+ # Override DB_NAME so multiple can run in parallel
34
+ run(
35
+ "DB_NAME=#{db_name} BUNDLE_GEMFILE='#{gem_file_path}' bin/rails #{base_command} #{args.join(' ')}",
36
+ { abort_on_failure: true }
37
+ )
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dotenv"
4
+ require "rails/command"
5
+
6
+ module Rails
7
+ module Command
8
+ module Rhino
9
+ module Module
10
+ class DummyCommand < Base # :nodoc:
11
+ include Thor::Actions
12
+
13
+ def perform(*args)
14
+ rhino_command("test/dummy", nil, *args)
15
+ end
16
+
17
+ protected
18
+ def rhino_command(extra_path, base_command, *args) # rubocop:todo Metrics/MethodLength
19
+ module_name = if Dir.exist?(args[0])
20
+ args.shift
21
+ else
22
+ abort "No module specified"
23
+ end
24
+ module_path = [module_name, extra_path].compact.join("/")
25
+ db_name = "#{module_name}_dummy"
26
+ gem_file_path = File.join(Dir.pwd, "Gemfile")
27
+
28
+ # Getting existing variables and re-use
29
+ ::Dotenv.load
30
+
31
+ inside(module_path) do
32
+ # Override DB_NAME so multiple can run in parallel
33
+ run(
34
+ "DB_NAME=#{db_name} BUNDLE_GEMFILE='#{gem_file_path}' bin/rails #{base_command} #{args.join(' ')}",
35
+ { abort_on_failure: true }
36
+ )
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dotenv"
4
+ require "rails/command"
5
+
6
+ module Rails
7
+ module Command
8
+ module Rhino
9
+ module Module
10
+ class NewCommand < Base # :nodoc:
11
+ no_commands do
12
+ def help
13
+ run_module_generator %w[--help]
14
+ end
15
+ end
16
+
17
+ def self.banner(*) # :nodoc:
18
+ "#{executable} new [options]"
19
+ end
20
+
21
+ def perform(*args)
22
+ run_module_generator(args)
23
+ end
24
+
25
+ private
26
+ def run_module_generator(plugin_args)
27
+ require "generators/rhino/module/module_generator"
28
+ ::Rhino::Generators::ModuleGenerator.start plugin_args
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dotenv"
4
+ require "rails/command"
5
+
6
+ module Rails
7
+ module Command
8
+ module Rhino
9
+ module Module
10
+ class RailsCommand < Base # :nodoc:
11
+ include Thor::Actions
12
+
13
+ def perform(*args)
14
+ rhino_command(nil, nil, *args)
15
+ end
16
+
17
+ protected
18
+ def rhino_command(extra_path, base_command, *args) # rubocop:todo Metrics/MethodLength
19
+ module_name = if Dir.exist?(args[0])
20
+ args.shift
21
+ else
22
+ abort "No module specified"
23
+ end
24
+ module_path = [module_name, extra_path].compact.join("/")
25
+ db_name = "#{module_name}_dummy"
26
+ gem_file_path = File.join(Dir.pwd, "Gemfile")
27
+
28
+ # Getting existing variables and re-use
29
+ ::Dotenv.load
30
+
31
+ inside(module_path) do
32
+ # Override DB_NAME so multiple can run in parallel
33
+ run(
34
+ "DB_NAME=#{db_name} BUNDLE_GEMFILE='#{gem_file_path}' bin/rails #{base_command} #{args.join(' ')}",
35
+ { abort_on_failure: true }
36
+ )
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dotenv"
4
+ require "rails/command"
5
+
6
+ module Rails
7
+ module Command
8
+ module Rhino
9
+ module Module
10
+ class TestCommand < Base # :nodoc:
11
+ include Thor::Actions
12
+
13
+ def test(*args)
14
+ rhino_command(nil, "test", *args)
15
+ end
16
+
17
+ protected
18
+ def rhino_command(extra_path, base_command, *args) # rubocop:todo Metrics/MethodLength
19
+ module_name = if Dir.exist?(args[0])
20
+ args.shift
21
+ else
22
+ abort "No module specified"
23
+ end
24
+ module_path = [module_name, extra_path].compact.join("/")
25
+ db_name = "#{module_name}_dummy"
26
+ gem_file_path = File.join(Dir.pwd, "Gemfile")
27
+
28
+ # Getting existing variables and re-use
29
+ ::Dotenv.load
30
+
31
+ inside(module_path) do
32
+ # Override DB_NAME so multiple can run in parallel
33
+ run(
34
+ "DB_NAME=#{db_name} BUNDLE_GEMFILE='#{gem_file_path}' bin/rails #{base_command} #{args.join(' ')}",
35
+ { abort_on_failure: true }
36
+ )
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,199 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rhino
4
+ module Generators
5
+ module Dev
6
+ # rubocop:disable Metrics/ClassLength
7
+ class SetupGenerator < ::Rails::Generators::Base
8
+ DEFAULT_SERVER_PORT = 3000
9
+ DEFAULT_CLIENT_PORT = DEFAULT_SERVER_PORT + 1
10
+
11
+ class_option :prompt, type: :boolean, default: true, desc: "Prompt user for configuration options"
12
+ class_option :defaults, type: :string, enum: %w[local docker], default: "local", desc: "Use configuration defaults of type DEFAULTS"
13
+ class_option :skip_existing, type: :boolean, default: false, desc: "Skip existing env files"
14
+ class_option :server_port, type: :numeric, default: DEFAULT_SERVER_PORT, group: :server, desc: "Server port"
15
+ class_option :client_port, type: :numeric, default: DEFAULT_CLIENT_PORT, group: :client, desc: "Client port"
16
+ class_option :db_host, type: :string, group: :database
17
+ class_option :db_name, type: :string, group: :database
18
+ class_option :db_port, type: :numeric, default: 5432, group: :database
19
+ class_option :db_user, type: :string, group: :database
20
+ class_option :db_password, type: :string, group: :database
21
+ class_option :redis_port, type: :numeric, default: 6379, group: :redis
22
+ class_option :redis_database, type: :numeric, default: 0, group: :redis
23
+
24
+ attr_reader :server_port,
25
+ :client_port,
26
+ :db_name,
27
+ :db_host,
28
+ :db_port,
29
+ :db_user,
30
+ :db_password,
31
+ :redis_host,
32
+ :redis_port,
33
+ :redis_database,
34
+ :dockerized
35
+
36
+ source_root File.expand_path("templates", __dir__)
37
+
38
+ def check_existing
39
+ return unless options[:skip_existing] && File.exist?(server_file(".env"))
40
+
41
+ say "Skipping existing .env files"
42
+ exit(0)
43
+ end
44
+
45
+ def setup_env
46
+ say "Setting up local .env files"
47
+
48
+ collect_env_info
49
+
50
+ template "env.root", project_file(".env")
51
+ template "env.server", server_file(".env")
52
+ template "env.client", client_file(".env")
53
+ end
54
+
55
+ def install_hooks
56
+ say "Installing git hooks"
57
+ # Hooks need to be executable
58
+ copy_file "prepare-commit-msg",
59
+ project_file(".git/hooks/prepare-commit-msg"),
60
+ mode: :preserve
61
+ end
62
+
63
+ private
64
+ def project_dir
65
+ # Up one level from the server directory
66
+ Rails.root.parent
67
+ end
68
+
69
+ def server_extension
70
+ Rails.root.basename.to_s.match(/[-_]?server/)[0]
71
+ end
72
+
73
+ def server_port_default
74
+ options[:server_port] || ENV["PORT"]
75
+ end
76
+
77
+ def client_port_default
78
+ @server_port.to_i + 1
79
+ end
80
+
81
+ def project_name
82
+ @project_name ||= File.basename(project_dir).sub(/[-_]?mono/, "")
83
+ end
84
+
85
+ def db_name_default
86
+ db_name = options[:db_name] || ENV["DB_NAME"] || project_name
87
+
88
+ return db_name if db_name.present?
89
+
90
+ File.basename(Rails.root.parent)
91
+ end
92
+
93
+ def db_host_default
94
+ options[:db_host] || ENV["DB_HOST"] || "localhost"
95
+ end
96
+
97
+ def db_port_default
98
+ options[:db_port] || ENV["DB_PORT"]
99
+ end
100
+
101
+ def db_user_default
102
+ options[:db_user] || ENV["DB_USERNAME"] || `whoami`
103
+ end
104
+
105
+ def db_password_default
106
+ options[:db_password] || ENV["DB_PASSWORD"] || ""
107
+ end
108
+
109
+ def redis_host_default
110
+ options[:redis_host] || ENV["REDIS_HOST"] || "localhost"
111
+ end
112
+
113
+ def redis_port_default
114
+ options[:redis_port] || ENV["REDIS_PORT"]
115
+ end
116
+
117
+ def redis_database_default
118
+ options[:redis_database] || ENV["REDIS_DATABASE"]
119
+ end
120
+
121
+ def dockerized_default
122
+ options[:defaults] == "docker" ? "Y" : "N"
123
+ end
124
+
125
+ def collect_env_info
126
+ collect_docker_info
127
+
128
+ @server_port = ask_prompt("Server Port?", server_port_default)
129
+ @client_port = ask_prompt("Client Port?", client_port_default)
130
+
131
+ collect_database_info
132
+ collect_redis_info
133
+ end
134
+
135
+ def collect_docker_info
136
+ @dockerized = %w[y Y].include?(ask_prompt("Run with docker?", dockerized_default))
137
+
138
+ return unless dockerized
139
+
140
+ @db_host = "db"
141
+ @db_user = "postgres"
142
+ @db_password = "password"
143
+ @db_port = 5432
144
+ @redis_host = "redis"
145
+ @redis_port = 6379
146
+ @redis_database = 0
147
+
148
+ puts <<~HERE
149
+ The following docker configuration has been automatically set for you:
150
+ Database host: #{db_host}
151
+ Database port: #{db_port}
152
+ Database user: #{db_user}
153
+ Database password: #{db_password}
154
+ Redis host: #{redis_host}
155
+ Redis port: #{redis_port}
156
+ Redis database: #{redis_database}
157
+ HERE
158
+ end
159
+
160
+ def collect_database_info
161
+ @db_name = ask_prompt("Database?", db_name_default)
162
+ @db_host ||= ask_prompt("Database host?", db_host_default)
163
+ @db_port ||= ask_prompt("Database port?", db_port_default)
164
+ @db_user ||= ask_prompt("Database User?", db_user_default)
165
+ @db_password ||= ask_prompt("Database Password?", db_password_default)
166
+
167
+ nil
168
+ end
169
+
170
+ def collect_redis_info
171
+ @redis_host ||= ask_prompt("Redis host?", redis_host_default)
172
+ @redis_port ||= ask_prompt("Redis port?", redis_port_default)
173
+ @redis_database ||= ask_prompt("Redis database?", redis_database_default)
174
+
175
+ nil
176
+ end
177
+
178
+ def project_file(file)
179
+ File.join(project_dir, file)
180
+ end
181
+
182
+ def client_file(file)
183
+ File.join(project_dir, "client", file)
184
+ end
185
+
186
+ def server_file(file)
187
+ File.join(project_dir, "server", file)
188
+ end
189
+
190
+ def ask_prompt(message, default)
191
+ return default unless options[:prompt]
192
+
193
+ ask(message, default:)
194
+ end
195
+ end
196
+ # rubocop:enable Metrics/ClassLength
197
+ end
198
+ end
199
+ end
@@ -0,0 +1,4 @@
1
+ PORT=<%= client_port %>
2
+
3
+ VITE_API_ROOT_PATH=http://localhost:<%= server_port %>
4
+ VITE_ROLLBAR_ACCESS_TOKEN=
@@ -0,0 +1 @@
1
+ COMPOSE_PROJECT_NAME=<%= project_name %>
@@ -0,0 +1,35 @@
1
+ PORT=<%= server_port %>
2
+
3
+ ROOT_URL=http://localhost:<%= server_port %>
4
+ FRONT_END_URL=http://localhost:<%= client_port %>
5
+
6
+ DB_NAME=<%= db_name %>
7
+ DB_HOST=<%= db_host %>
8
+ DB_PORT=<%= db_port %>
9
+ DB_USERNAME=<%= db_user %>
10
+ DB_PASSWORD=<%= db_password %>
11
+ REDIS_HOST=<%= redis_host %>
12
+ REDIS_PORT=<%= redis_port %>
13
+ REDIS_DATABASE=<%= redis_database %>
14
+
15
+ SECRET_KEY_BASE=0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
16
+
17
+ # Production only:
18
+ SENDGRID_API_KEY=<api-key>
19
+
20
+ #AWS_ACCESS_KEY=
21
+ #AWS_SECRET_KEY=
22
+ #AWS_S3_BUCKET=
23
+ #AWS_REGION=
24
+
25
+ #AZURE_STORAGE_KEY=AAAAAAAAAAAAAA
26
+ #AZURE_ACCOUNT_NAME="azure_acc_name"
27
+ #AZURE_CONTAINER="container-test"
28
+
29
+ #STRIPE_PUBLISHABLE_KEY=pk_...
30
+ #STRIPE_SECRET_KEY=sk_...
31
+
32
+ #AUTH_GOOGLE_OAUTH2_CLIENT_ID=
33
+ #AUTH_GOOGLE_OAUTH2_SECRET_KEY=
34
+
35
+ ROLLBAR_ACCESS_TOKEN=
@@ -0,0 +1,17 @@
1
+ #!/bin/bash
2
+
3
+ # This way you can customize which branches should be skipped when
4
+ # prepending commit message.
5
+ if [ -z "$BRANCHES_TO_SKIP" ]; then
6
+ BRANCHES_TO_SKIP=(main master develop test)
7
+ fi
8
+
9
+ BRANCH_NAME=$(git symbolic-ref --short HEAD)
10
+ BRANCH_NAME="${BRANCH_NAME##*/}"
11
+
12
+ BRANCH_EXCLUDED=$(printf "%s\n" "${BRANCHES_TO_SKIP[@]}" | grep -c "^$BRANCH_NAME$")
13
+ BRANCH_IN_COMMIT=$(grep -c "\[$BRANCH_NAME\]" $1)
14
+
15
+ if [ -n "$BRANCH_NAME" ] && ! [[ $BRANCH_EXCLUDED -eq 1 ]] && ! [[ $BRANCH_IN_COMMIT -ge 1 ]]; then
16
+ sed -i.bak -e "1s/^/[$BRANCH_NAME] /" $1
17
+ fi