bullet_train-super_scaffolding 1.0.2 → 1.0.6

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: fad70b09de2e66feebad90398591dc8022a19eb29d431cf6cc4bf9211c9ff2b7
4
- data.tar.gz: 274eb7661ee67564d1856674af6a7e554fc1bae87795a5614fb6bca537ab4669
3
+ metadata.gz: ce5d6f3d2cb0ff2a0ed85aa5928e2a9e390b17709b41889c0fb6c25b9d7c4293
4
+ data.tar.gz: af398b0b3cbc631f42e38d8643899678399bf1d7e819a1261f0142980029ec97
5
5
  SHA512:
6
- metadata.gz: aa68a6e711a10f484b7a59b1fec2928679022ac34b6d91963dee1121ad0f0a906c55bc8715f523a390cc81589ed2bf21090e3caa5cda60ab5dac44fdb85f7641
7
- data.tar.gz: 9009df2aad5105f58baa3825883019e6c2d1cb62872811ca8ffcfda8c7e902165b7278ba0aad384c183151241eeed94fc10e7084a24dca664b9ee5b84fa835f1
6
+ metadata.gz: 6a1450d9449295670cd943ad637da3405b6b509c09905520c93bfdbab32eb471d93eedd3df5915db3cf325d77a5bd2d0ea8b4add6cf29b9811aba12b4242d74b
7
+ data.tar.gz: f5c3879c59b9ed29c0982856e206e569756f6861f5f80784ef6ae04cdc5cd315771adfebdb18bcf3b7ae0a7aa32482ddf7c9f025f90befc7f7632b7c38f18cda
@@ -0,0 +1,13 @@
1
+ module BulletTrain
2
+ module SuperScaffolding
3
+ class Scaffolder
4
+ attr_accessor :argv
5
+
6
+ def initialize(argv, options)
7
+ # Just setting these like this so the code we moved around still runs.
8
+ self.argv = argv
9
+ @options = options
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,44 @@
1
+ module BulletTrain
2
+ module SuperScaffolding
3
+ module Scaffolders
4
+ class CrudFieldScaffolder < Scaffolder
5
+ def run
6
+ unless argv.count >= 2
7
+ puts ""
8
+ puts "🚅 usage: bin/super-scaffold crud-field <Model> <attribute:type> <attribute:type> ... [options]"
9
+ puts ""
10
+ puts "E.g. add a description and body to Pages:"
11
+ puts " rails g migration add_description_etc_to_pages description:text body:text"
12
+ puts " bin/super-scaffold crud-field Page description:text body:text"
13
+ puts ""
14
+ puts "Options:"
15
+ puts ""
16
+ puts " --skip-table: Only add to the new/edit form and show view."
17
+ puts ""
18
+ exit
19
+ end
20
+
21
+ # We pass this value to parents to create a new Scaffolding::Transformer because
22
+ # we don't actually need knowledge of the parent to add the new field.
23
+ parents = [""]
24
+ child = argv[0]
25
+
26
+ # get all the attributes.
27
+ attributes = argv[1..-1]
28
+
29
+ check_required_options_for_attributes('crud-field', attributes, child)
30
+
31
+ transformer = Scaffolding::Transformer.new(child, parents, @options)
32
+ transformer.add_attributes_to_various_views(attributes, type: :crud_field)
33
+
34
+ transformer.additional_steps.uniq.each_with_index do |additional_step, index|
35
+ color, message = additional_step
36
+ puts ""
37
+ puts "#{index + 1}. #{message}".send(color)
38
+ end
39
+ puts ""
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,65 @@
1
+ module BulletTrain
2
+ module SuperScaffolding
3
+ module Scaffolders
4
+ class CrudScaffolder < Scaffolder
5
+ def run
6
+ unless argv.count >= 3
7
+ puts ""
8
+ puts "🚅 usage: bin/super-scaffold crud <Model> <ParentModel[s]> <attribute:type> <attribute:type> ..."
9
+ puts ""
10
+ puts "E.g. a Team has many Sites with some attributes:"
11
+ puts " rails g model Site team:references name:string url:text"
12
+ puts " bin/super-scaffold crud Site Team name:string url:text"
13
+ puts ""
14
+ puts "E.g. a Section belongs to a Page, which belongs to a Site, which belongs to a Team:"
15
+ puts " rails g model Section page:references title:text body:text"
16
+ puts " bin/super-scaffold crud Section Page,Site,Team title:text body:text"
17
+ puts ""
18
+ puts "E.g. an Image belongs to either a Page or a Site:"
19
+ puts " Doable! See https://bit.ly/2NvO8El for a step by step guide."
20
+ puts ""
21
+ puts "E.g. Pages belong to a Site and are sortable via drag-and-drop:"
22
+ puts " rails g model Page site:references name:string path:text"
23
+ puts " bin/super-scaffold crud Page Site,Team name:text path:text --sortable"
24
+ puts ""
25
+ puts "🏆 Protip: Commit your other changes before running Super Scaffolding so it's easy to undo if you (or we) make any mistakes."
26
+ puts "If you do that, you can reset to your last commit state by using `git checkout .` and `git clean -d -f` ."
27
+ puts ""
28
+ puts "Give it a shot! Let us know if you have any trouble with it! ✌️"
29
+ puts ""
30
+ exit
31
+ end
32
+
33
+ child = argv[0]
34
+ parents = argv[1] ? argv[1].split(",") : []
35
+ parents = parents.map(&:classify).uniq
36
+ parent = parents.first
37
+
38
+ unless parents.include?("Team")
39
+ raise "Parents for #{child} should trace back to the Team model, but Team wasn't provided. Please confirm that all of the parents tracing back to the Team model are present and try again.\n" +
40
+ "E.g.:\n" +
41
+ "rails g model Section page:references title:text body:text\n" +
42
+ "bin/super-scaffold crud Section Page,Site,Team title:text body:text\n"
43
+ end
44
+
45
+ # get all the attributes.
46
+ attributes = argv[2..-1]
47
+
48
+ check_required_options_for_attributes('crud', attributes, child, parent)
49
+
50
+ binding.pry
51
+
52
+ transformer = Scaffolding::Transformer.new(child, parents, @options)
53
+ transformer.scaffold_crud(attributes)
54
+
55
+ transformer.additional_steps.each_with_index do |additional_step, index|
56
+ color, message = additional_step
57
+ puts ""
58
+ puts "#{index + 1}. #{message}".send(color)
59
+ end
60
+ puts ""
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,96 @@
1
+ module BulletTrain
2
+ module SuperScaffolding
3
+ module Scaffolders
4
+ class JoinModelScaffolder < Scaffolder
5
+ def run
6
+ unless argv.count >= 3
7
+ puts ""
8
+ puts "🚅 usage: bin/super-scaffold join-model <JoinModel> <left_association> <right_association>"
9
+ puts ""
10
+ puts "E.g. Add project-specific tags to a project:"
11
+ puts ""
12
+ puts " Given the following example models:".blue
13
+ puts ""
14
+ puts " rails g model Project team:references name:string description:text"
15
+ puts " bin/super-scaffold crud Project Team name:text_field description:trix_editor"
16
+ puts ""
17
+ puts " rails g model Projects::Tag team:references name:string"
18
+ puts " bin/super-scaffold crud Projects::Tag Team name:text_field"
19
+ puts ""
20
+ puts " 1️⃣ Use the standard Rails model generator to generate the join model:".blue
21
+ puts ""
22
+ puts " rails g model Projects::AppliedTag project:references tag:references"
23
+ puts ""
24
+ puts " 👋 Don't run migrations yet! Sometimes Super Scaffolding updates them for you.".yellow
25
+ puts ""
26
+ puts " 2️⃣ Use `join-model` scaffolding to prepare the join model for use in `crud-field` scaffolding:".blue
27
+ puts ""
28
+ puts " bin/super-scaffold join-model Projects::AppliedTag project_id[class_name=Project] tag_id[class_name=Projects::Tag]"
29
+ puts ""
30
+ puts " 3️⃣ Now you can use `crud-field` scaffolding to actually add the field to the form of the parent model:".blue
31
+ puts ""
32
+ puts " bin/super-scaffold crud-field Project tag_ids:super_select[class_name=Projects::Tag]"
33
+ puts ""
34
+ puts " 👋 Heads up! There will be one follow-up step output by this command that you need to take action on."
35
+ puts ""
36
+ puts " 4️⃣ Now you can run your migrations.".blue
37
+ exit
38
+ end
39
+
40
+ child = argv[0]
41
+ primary_parent = argv[1].split("class_name=").last.split(",").first.split("]").first
42
+ secondary_parent = argv[2].split("class_name=").last.split(",").first.split("]").first
43
+
44
+ # There should only be two attributes.
45
+ attributes = [argv[1], argv[2]]
46
+
47
+ # Pretend we're doing a `super_select` scaffolding because it will do the correct thing.
48
+ attributes = attributes.map { |attribute| attribute.gsub("\[", ":super_select\[") }
49
+ attributes = attributes.map { |attribute| attribute.gsub("\]", ",required\]") }
50
+
51
+ transformer = Scaffolding::Transformer.new(child, [primary_parent], @options)
52
+
53
+ # We need this transformer to reflect on the class names _just_ between e.g. `Project` and `Projects::Tag`, without the join model.
54
+ has_many_through_transformer = Scaffolding::Transformer.new(secondary_parent, [primary_parent], @options)
55
+
56
+ # We need this transformer to reflect on the association between `Projects::Tag` and `Projects::AppliedTag` backwards.
57
+ inverse_transformer = Scaffolding::Transformer.new(child, [secondary_parent], @options)
58
+
59
+ # We need this transformer to reflect on the class names _just_ between e.g. `Projects::Tag` and `Project`, without the join model.
60
+ inverse_has_many_through_transformer = Scaffolding::Transformer.new(primary_parent, [secondary_parent], @options)
61
+
62
+ # However, for the first attribute, we actually don't need the scope validator (and can't really implement it).
63
+ attributes[0] = attributes[0].gsub("\]", ",unscoped\]")
64
+
65
+ has_many_through_association = has_many_through_transformer.transform_string("completely_concrete_tangible_things")
66
+ source = transformer.transform_string("absolutely_abstract_creative_concept.valid_$HAS_MANY_THROUGH_ASSOCIATION")
67
+ source.gsub!("$HAS_MANY_THROUGH_ASSOCIATION", has_many_through_association)
68
+
69
+ # For the second one, we don't want users to have to define the list of valid options in the join model, so we do this:
70
+ attributes[1] = attributes[1].gsub("\]", ",source=#{source}\]")
71
+
72
+ # This model hasn't been crud scaffolded, so a bunch of views are skipped here, but that's OK!
73
+ # It does what we need on the files that exist.
74
+ transformer.add_scaffolding_hooks_to_model
75
+
76
+ transformer.suppress_could_not_find = true
77
+ transformer.add_attributes_to_various_views(attributes, type: :crud_field)
78
+ transformer.suppress_could_not_find = false
79
+
80
+ # Add the `has_many ... through:` association in both directions.
81
+ transformer.add_has_many_through_associations(has_many_through_transformer)
82
+ inverse_transformer.add_has_many_through_associations(inverse_has_many_through_transformer)
83
+
84
+ additional_steps = (transformer.additional_steps + has_many_through_transformer.additional_steps + inverse_transformer.additional_steps + inverse_has_many_through_transformer.additional_steps).uniq
85
+
86
+ additional_steps.each_with_index do |additional_step, index|
87
+ color, message = additional_step
88
+ puts ""
89
+ puts "#{index + 1}. #{message}".send(color)
90
+ end
91
+ puts ""
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,173 @@
1
+ module BulletTrain
2
+ module SuperScaffolding
3
+ module Scaffolders
4
+ class OauthProviderScaffolder < Scaffolder
5
+ def run
6
+ unless argv.count >= 5
7
+ puts ""
8
+ puts "🚅 usage: bin/super-scaffold oauth-provider <omniauth_gem> <gems_provider_name> <our_provider_name> <PROVIDER_API_KEY_IN_ENV> <PROVIDER_API_SECRET_IN_ENV> [options]"
9
+ puts ""
10
+ puts "E.g. what we'd do to start Stripe off (if we didn't already do it):"
11
+ puts " bin/super-scaffold oauth-provider omniauth-stripe-connect stripe_connect Oauth::StripeAccount STRIPE_CLIENT_ID STRIPE_SECRET_KEY --icon=ti-money"
12
+ puts ""
13
+ puts "E.g. what we actually did to start Shopify off:"
14
+ puts " bin/super-scaffold oauth-provider omniauth-shopify-oauth2 shopify Oauth::ShopifyAccount SHOPIFY_API_KEY SHOPIFY_API_SECRET_KEY --icon=ti-shopping-cart"
15
+ puts ""
16
+ puts "Options:"
17
+ puts ""
18
+ puts " --icon={ti-*}: Specify an icon."
19
+ puts ""
20
+ puts "For a list of readily available provider strategies, see https://github.com/omniauth/omniauth/wiki/List-of-Strategies ."
21
+ puts ""
22
+ exit
23
+ end
24
+
25
+ _, omniauth_gem, gems_provider_name, our_provider_name, api_key, api_secret = *ARGV
26
+
27
+ unless match = our_provider_name.match(/Oauth::(.*)Account/)
28
+ puts "\n🚨 Your provider name must match the pattern of `Oauth::{Name}Account`, e.g. `Oauth::StripeAccount`\n".red
29
+ return
30
+ end
31
+
32
+ options = {
33
+ omniauth_gem: omniauth_gem,
34
+ gems_provider_name: gems_provider_name,
35
+ our_provider_name: match[1],
36
+ api_key: api_key,
37
+ api_secret: api_secret
38
+ }
39
+
40
+ unless File.exist?(oauth_transform_string("./app/models/oauth/stripe_account.rb", options)) &&
41
+ File.exist?(oauth_transform_string("./app/models/integrations/stripe_installation.rb", options)) &&
42
+ File.exist?(oauth_transform_string("./app/models/webhooks/incoming/oauth/stripe_account_webhook.rb", options))
43
+ puts ""
44
+ puts oauth_transform_string("🚨 Before doing the actual Super Scaffolding, you'll need to generate the models like so:", options).red
45
+ puts ""
46
+ puts oauth_transform_string(" rails g model Oauth::StripeAccount uid:string data:jsonb user:references", options).red
47
+ puts oauth_transform_string(" rails g model Integrations::StripeInstallation team:references oauth_stripe_account:references name:string", options).red
48
+ puts oauth_transform_string(" rails g model Webhooks::Incoming::Oauth::StripeAccountWebhook data:jsonb processed_at:datetime verified_at:datetime oauth_stripe_account:references", options).red
49
+ puts ""
50
+ puts "However, don't do the `rake db:migrate` until after you re-run Super Scaffolding, as it will need to update some settings in those migrations.".red
51
+ puts ""
52
+ return
53
+ end
54
+
55
+ icon_name = nil
56
+ if @options["icon"].present?
57
+ icon_name = @options["icon"]
58
+ else
59
+ puts "OK, great! Let's do this! By default providers will appear with a dollar symbol,"
60
+ puts "but after you hit enter I'll open a page where you can view other icon options."
61
+ puts "When you find one you like, hover your mouse over it and then come back here and"
62
+ puts "and enter the name of the icon you want to use."
63
+ response = STDIN.gets.chomp
64
+ `open http://light.pinsupreme.com/icon_fonts_themefy.html`
65
+ puts ""
66
+ puts "Did you find an icon you wanted to use? Enter the name here or hit enter to just"
67
+ puts "use the dollar symbol:"
68
+ icon_name = STDIN.gets.chomp
69
+ puts ""
70
+ unless icon_name.length > 0 || icon_name.downcase == "y"
71
+ icon_name = "icon-puzzle"
72
+ end
73
+ end
74
+
75
+ options[:icon] = icon_name
76
+
77
+ [
78
+
79
+ # User OAuth.
80
+ "./app/models/oauth/stripe_account.rb",
81
+ "./app/models/webhooks/incoming/oauth/stripe_account_webhook.rb",
82
+ "./app/controllers/account/oauth/stripe_accounts_controller.rb",
83
+ "./app/controllers/webhooks/incoming/oauth/stripe_account_webhooks_controller.rb",
84
+ "./app/views/account/oauth/stripe_accounts",
85
+ "./test/models/oauth/stripe_account_test.rb",
86
+ "./test/factories/oauth/stripe_accounts.rb",
87
+ "./config/locales/en/oauth/stripe_accounts.en.yml",
88
+ "./app/views/devise/shared/oauth/_stripe.html.erb",
89
+
90
+ # Team Integration.
91
+ "./app/models/integrations/stripe_installation.rb",
92
+ # './app/serializers/api/v1/integrations/stripe_installation_serializer.rb',
93
+ "./app/controllers/account/integrations/stripe_installations_controller.rb",
94
+ "./app/views/account/integrations/stripe_installations",
95
+ "./test/models/integrations/stripe_installation_test.rb",
96
+ "./test/factories/integrations/stripe_installations.rb",
97
+ "./config/locales/en/integrations/stripe_installations.en.yml",
98
+
99
+ # Webhook.
100
+ "./app/models/webhooks/incoming/oauth/stripe_account_webhook.rb",
101
+ "./app/controllers/webhooks/incoming/oauth/stripe_account_webhooks_controller.rb"
102
+
103
+ ].each do |name|
104
+ if File.directory?(name)
105
+ oauth_scaffold_directory(name, options)
106
+ else
107
+ oauth_scaffold_file(name, options)
108
+ end
109
+ end
110
+
111
+ oauth_scaffold_add_line_to_file("./app/views/devise/shared/_oauth.html.erb", "<%= render 'devise/shared/oauth/stripe', verb: verb if stripe_enabled? %>", "<%# 🚅 super scaffolding will insert new oauth providers above this line. %>", options, prepend: true)
112
+ oauth_scaffold_add_line_to_file("./app/views/account/users/edit.html.erb", "<%= render 'account/oauth/stripe_accounts/index', context: @user, stripe_accounts: @user.oauth_stripe_accounts if stripe_enabled? %>", "<% # 🚅 super scaffolding will insert new oauth providers above this line. %>", options, prepend: true)
113
+ oauth_scaffold_add_line_to_file("./config/initializers/devise.rb", "config.omniauth :stripe_connect, ENV['STRIPE_CLIENT_ID'], ENV['STRIPE_SECRET_KEY'], {\n ## specify options for your oauth provider here, e.g.:\n # scope: 'read_products,read_orders,write_content',\n }\n", "# 🚅 super scaffolding will insert new oauth providers above this line.", options, prepend: true)
114
+ oauth_scaffold_add_line_to_file("./app/controllers/account/oauth/omniauth_callbacks_controller.rb", "def stripe_connect\n callback(\"Stripe\", team_id_from_env)\n end\n", "# 🚅 super scaffolding will insert new oauth providers above this line.", options, prepend: true)
115
+ oauth_scaffold_add_line_to_file("./app/models/team.rb", "has_many :integrations_stripe_installations, class_name: 'Integrations::StripeInstallation', dependent: :destroy if stripe_enabled?", "# 🚅 add oauth providers above.", options, prepend: true)
116
+ oauth_scaffold_add_line_to_file("./app/models/user.rb", "has_many :oauth_stripe_accounts, class_name: 'Oauth::StripeAccount' if stripe_enabled?", "# 🚅 add oauth providers above.", options, prepend: true)
117
+ oauth_scaffold_add_line_to_file("./config/locales/en/oauth.en.yml", "stripe_connect: Stripe", "# 🚅 super scaffolding will insert new oauth providers above this line.", options, prepend: true)
118
+ oauth_scaffold_add_line_to_file("./app/views/account/shared/_menu.html.erb", "<%= render 'account/integrations/stripe_installations/menu_item' if stripe_enabled? %>", "<%# 🚅 super scaffolding will insert new oauth providers above this line. %>", options, prepend: true)
119
+ oauth_scaffold_add_line_to_file("./config/routes.rb", "resources :stripe_account_webhooks if stripe_enabled?", "# 🚅 super scaffolding will insert new oauth provider webhooks above this line.", options, prepend: true)
120
+ oauth_scaffold_add_line_to_file("./config/routes.rb", "resources :stripe_accounts if stripe_enabled?", "# 🚅 super scaffolding will insert new oauth providers above this line.", options, prepend: true)
121
+ oauth_scaffold_add_line_to_file("./config/routes.rb", "resources :stripe_installations if stripe_enabled?", "# 🚅 super scaffolding will insert new integration installations above this line.", options, prepend: true)
122
+ oauth_scaffold_add_line_to_file("./Gemfile", "gem 'omniauth-stripe-connect'", "# 🚅 super scaffolding will insert new oauth providers above this line.", options, prepend: true)
123
+ oauth_scaffold_add_line_to_file("./lib/bullet_train.rb", "def stripe_enabled?\n ENV['STRIPE_CLIENT_ID'].present? && ENV['STRIPE_SECRET_KEY'].present?\nend\n", "# 🚅 super scaffolding will insert new oauth providers above this line.", options, prepend: true)
124
+ oauth_scaffold_add_line_to_file("./lib/bullet_train.rb", "stripe_enabled?,", "# 🚅 super scaffolding will insert new oauth provider checks above this line.", options, prepend: true)
125
+ oauth_scaffold_add_line_to_file("./app/models/ability.rb", "if stripe_enabled?
126
+ can [:read, :create, :destroy], Oauth::StripeAccount, user_id: user.id
127
+ can :manage, Integrations::StripeInstallation, team_id: user.team_ids
128
+ can :destroy, Integrations::StripeInstallation, oauth_stripe_account: {user_id: user.id}
129
+ end
130
+ ", "# 🚅 super scaffolding will insert any new oauth providers above.", options, prepend: true)
131
+
132
+ # find the database migration that defines this relationship.
133
+ migration_file_name = `grep "create_table #{oauth_transform_string(":oauth_stripe_accounts", options)}" db/migrate/*`.split(":").first
134
+ legacy_replace_in_file(migration_file_name, "null: false", "null: true")
135
+
136
+ migration_file_name = `grep "create_table #{oauth_transform_string(":integrations_stripe_installations", options)}" db/migrate/*`.split(":").first
137
+ legacy_replace_in_file(migration_file_name,
138
+ oauth_transform_string("t.references :oauth_stripe_account, null: false, foreign_key: true", options),
139
+ oauth_transform_string('t.references :oauth_stripe_account, null: false, foreign_key: true, index: {name: "index_stripe_installations_on_oauth_stripe_account_id"}', options))
140
+
141
+ migration_file_name = `grep "create_table #{oauth_transform_string(":webhooks_incoming_oauth_stripe_account_webhooks", options)}" db/migrate/*`.split(":").first
142
+ legacy_replace_in_file(migration_file_name, "null: false", "null: true")
143
+ legacy_replace_in_file(migration_file_name, "foreign_key: true", 'foreign_key: true, index: {name: "index_stripe_webhooks_on_oauth_stripe_account_id"}')
144
+
145
+ puts ""
146
+ puts "🎉"
147
+ puts ""
148
+ puts "You'll probably need to `bundle install`.".green
149
+ puts ""
150
+ puts "If the OAuth provider asks you for some whitelisted callback URLs, the URL structure for those is as so:"
151
+ puts ""
152
+ path = "users/auth/stripe_connect/callback"
153
+ puts oauth_transform_string(" https://yourdomain.co/#{path}", options)
154
+ puts oauth_transform_string(" https://yourtunnel.ngrok.io/#{path}", options)
155
+ puts oauth_transform_string(" http://localhost:3000/#{path}", options)
156
+ puts ""
157
+ puts "If you're able to specify an endpoint to receive webhooks from this provider, use this URL:"
158
+ puts ""
159
+ path = "webhooks/incoming/oauth/stripe_account_webhooks"
160
+ puts oauth_transform_string(" https://yourdomain.co/#{path}", options)
161
+ puts oauth_transform_string(" https://yourtunnel.ngrok.io/#{path}", options)
162
+ puts oauth_transform_string(" http://localhost:3000/#{path}", options)
163
+ puts ""
164
+ puts ""
165
+ puts "If you'd like to edit how your Bullet Train application refers to this provider, just edit the locale file at `config/locales/en/oauth.en.yml`."
166
+ puts ""
167
+ puts "And finally, if you need to specify any custom authorizations or options for your OAuth integration with this provider, you can configure those in `config/initializers/devise.rb`."
168
+ puts ""
169
+ end
170
+ end
171
+ end
172
+ end
173
+ end
@@ -1,5 +1,5 @@
1
1
  module BulletTrain
2
2
  module SuperScaffolding
3
- VERSION = "1.0.2"
3
+ VERSION = "1.0.6"
4
4
  end
5
5
  end
@@ -1,15 +1,24 @@
1
1
  require "bullet_train/super_scaffolding/version"
2
2
  require "bullet_train/super_scaffolding/engine"
3
+ require "bullet_train/super_scaffolding/scaffolder"
4
+ require "bullet_train/super_scaffolding/scaffolders/crud_scaffolder"
5
+ require "bullet_train/super_scaffolding/scaffolders/crud_field_scaffolder"
6
+ require "bullet_train/super_scaffolding/scaffolders/join_model_scaffolder"
7
+ require "bullet_train/super_scaffolding/scaffolders/oauth_provider_scaffolder"
3
8
 
4
9
  module BulletTrain
5
10
  module SuperScaffolding
6
11
  mattr_accessor :template_paths, default: []
12
+ mattr_accessor :scaffolders, default: {
13
+ "crud" => "BulletTrain::SuperScaffolding::Scaffolders::CrudScaffolder",
14
+ "crud-field" => "BulletTrain::SuperScaffolding::Scaffolders::CrudFieldScaffolder",
15
+ "join-model" => "BulletTrain::SuperScaffolding::Scaffolders::JoinModelScaffolder",
16
+ "oauth-provider" => "BulletTrain::SuperScaffolding::Scaffolders::OauthProviderScaffolder",
17
+ }
7
18
 
8
19
  class Runner
9
20
  def run
10
21
  # Make `rake` invocation compatible with how this was run historically.
11
- ARGV.shift
12
-
13
22
  require "scaffolding/script"
14
23
  end
15
24
  end
@@ -0,0 +1,140 @@
1
+ class Scaffolding::BlockManipulator
2
+ attr_accessor :lines
3
+
4
+ def initialize(filepath)
5
+ @filepath = filepath
6
+ @lines = File.readlines(filepath)
7
+ end
8
+
9
+ #
10
+ # Wrap a block of ruby code inside another block
11
+ #
12
+ # @param [String] starting A string to search for at the start of the block. Eg "<%= updates_for context, collection do"
13
+ # @param [Array] with An array with two String elements. The text that should wrap the block. Eg ["<%= action_model_select_controller do %>", "<% end %>"]
14
+ #
15
+ def wrap_block(starting:, with:)
16
+ with[0] += "\n" unless with[0].match?(/\n$/)
17
+ with[1] += "\n" unless with[1].match?(/\n$/)
18
+ starting_line = find_block_start(starting)
19
+ end_line = find_block_end(starting_from: starting_line)
20
+
21
+ final = []
22
+ block_indent = ""
23
+ spacer = " "
24
+ @lines.each_with_index do |line, index|
25
+ line += "\n" unless line.match?(/\n$/)
26
+ if index < starting_line
27
+ final << line
28
+ elsif index == starting_line
29
+ block_indent = line.match(/^\s*/).to_s
30
+ final << block_indent + with[0]
31
+ final << (line.blank? ? "\n" : "#{spacer}#{line}")
32
+ elsif index > starting_line && index < end_line
33
+ final << (line.blank? ? "\n" : "#{spacer}#{line}")
34
+ elsif index == end_line
35
+ final << (line.blank? ? "\n" : "#{spacer}#{line}")
36
+ final << block_indent + with[1]
37
+ else
38
+ final << line
39
+ end
40
+ end
41
+
42
+ @lines = final
43
+ unless @lines.last.match?(/\n$/)
44
+ @lines.last += "\n"
45
+ end
46
+ end
47
+
48
+ def insert(content, within: nil, after: nil, before: nil, after_block: nil, append: false)
49
+ # Search for before like we do after, we'll just inject before it.
50
+ after ||= before
51
+
52
+ # If within is given, find the start and end lines of the block
53
+ content += "\n" unless content.match?(/\n$/)
54
+ start_line = 0
55
+ end_line = @lines.count - 1
56
+ if within.present?
57
+ start_line = find_block_start(within)
58
+ end_line = find_block_end(starting_from: start_line)
59
+ # start_line += 1 # ensure we actually insert the content _within_ the given block
60
+ # end_line += 1 if end_line == start_line
61
+ end
62
+ if after_block.present?
63
+ block_start = find_block_start(after_block)
64
+ block_end = find_block_end(starting_from: block_start)
65
+ start_line = block_end
66
+ end_line = @lines.count - 1
67
+ end
68
+ index = start_line
69
+ match = false
70
+ while index < end_line && !match
71
+ line = @lines[index]
72
+ if after.nil? || line.match?(after)
73
+ unless append
74
+ match = true
75
+ # We adjust the injection point if we really wanted to insert before.
76
+ insert_line(content, index - (before ? 1 : 0))
77
+ end
78
+ end
79
+ index += 1
80
+ end
81
+
82
+ return if match
83
+
84
+ # Match should always be false here.
85
+ if append && !match
86
+ insert_line(content, index - 1)
87
+ end
88
+ end
89
+
90
+ def insert_line(content, insert_at_index)
91
+ content += "\n" unless content.match?(/\n$/)
92
+ final = []
93
+ @lines.each_with_index do |line, index|
94
+ indent = line.match(/^\s*/).to_s
95
+ final << line
96
+ if index == insert_at_index
97
+ final << indent + content
98
+ end
99
+ end
100
+ @lines = final
101
+ end
102
+
103
+ def insert_block(block_content, after_block:)
104
+ block_start = find_block_start(after_block)
105
+ block_end = find_block_end(starting_from: block_start)
106
+ insert_line(block_content[0], block_end)
107
+ insert_line(block_content[1], block_end + 1)
108
+ end
109
+
110
+ def write
111
+ File.write(@filepath, @lines.join)
112
+ end
113
+
114
+ def find_block_start(starting_string)
115
+ matcher = Regexp.escape(starting_string)
116
+ starting_line = 0
117
+
118
+ @lines.each_with_index do |line, index|
119
+ if line.match?(matcher)
120
+ starting_line = index
121
+ break
122
+ end
123
+ end
124
+ starting_line
125
+ end
126
+
127
+ def find_block_end(starting_from:)
128
+ depth = 0
129
+ current_line = starting_from
130
+ @lines[starting_from..@lines.count].each_with_index do |line, index|
131
+ current_line = starting_from + index
132
+ depth += 1 if line.match?(/\s*<%.+ do .*%>/)
133
+ depth += 1 if line.match?(/\s*<% if .*%>/)
134
+ depth += 1 if line.match?(/\s*<% unless .*%>/)
135
+ depth -= 1 if line.match?(/\s*<%.* end .*%>/)
136
+ break current_line if depth == 0
137
+ end
138
+ current_line
139
+ end
140
+ end
@@ -1,3 +1,57 @@
1
+ def legacy_replace_in_file(file, before, after)
2
+ puts "Replacing in '#{file}'."
3
+ target_file_content = File.read(file)
4
+ target_file_content.gsub!(before, after)
5
+ File.write(file, target_file_content)
6
+ end
7
+
8
+ def legacy_add_line_to_file(file, content, hook, child, parent, options = {})
9
+ increase_indent = options[:increase_indent]
10
+ add_before = options[:add_before]
11
+ add_after = options[:add_after]
12
+
13
+ transformed_file_name = file
14
+ transformed_content = content
15
+ transform_hook = hook
16
+
17
+ target_file_content = File.read(transformed_file_name)
18
+
19
+ if target_file_content.include?(transformed_content)
20
+ puts "No need to update '#{transformed_file_name}'. It already has '#{transformed_content}'."
21
+ else
22
+ new_target_file_content = []
23
+ target_file_content.split("\n").each do |line|
24
+ if /#{Regexp.escape(transform_hook)}\s*$/.match?(line)
25
+
26
+ if add_before
27
+ new_target_file_content << "#{line} #{add_before}"
28
+ else
29
+ unless options[:prepend]
30
+ new_target_file_content << line
31
+ end
32
+ end
33
+
34
+ # get leading whitespace.
35
+ line =~ /^(\s*).*#{Regexp.escape(transform_hook)}.*/
36
+ leading_whitespace = $1
37
+ new_target_file_content << "#{leading_whitespace}#{" " if increase_indent}#{transformed_content}"
38
+
39
+ new_target_file_content << "#{leading_whitespace}#{add_after}" if add_after
40
+
41
+ if options[:prepend]
42
+ new_target_file_content << line
43
+ end
44
+ else
45
+ new_target_file_content << line
46
+ end
47
+ end
48
+
49
+ puts "Updating '#{transformed_file_name}'."
50
+
51
+ File.write(transformed_file_name, new_target_file_content.join("\n") + "\n")
52
+ end
53
+ end
54
+
1
55
  def encode_double_replacement_fix(string)
2
56
  string.chars.join("~!@BT@!~")
3
57
  end
@@ -1,64 +1,13 @@
1
1
  # TODO these methods were removed from the global scope in super scaffolding and moved to `Scaffolding::Transformer`,
2
2
  # but oauth provider scaffolding hasn't been updated yet.
3
3
 
4
+ require "scaffolding"
4
5
  require "scaffolding/transformer"
6
+ require "scaffolding/block_manipulator"
5
7
  require "scaffolding/class_names_transformer"
8
+ require "scaffolding/oauth_providers"
6
9
  require "scaffolding/routes_file_manipulator"
7
10
 
8
- def legacy_replace_in_file(file, before, after)
9
- puts "Replacing in '#{file}'."
10
- target_file_content = File.read(file)
11
- target_file_content.gsub!(before, after)
12
- File.write(file, target_file_content)
13
- end
14
-
15
- def legacy_add_line_to_file(file, content, hook, child, parent, options = {})
16
- increase_indent = options[:increase_indent]
17
- add_before = options[:add_before]
18
- add_after = options[:add_after]
19
-
20
- transformed_file_name = file
21
- transformed_content = content
22
- transform_hook = hook
23
-
24
- target_file_content = File.read(transformed_file_name)
25
-
26
- if target_file_content.include?(transformed_content)
27
- puts "No need to update '#{transformed_file_name}'. It already has '#{transformed_content}'."
28
- else
29
- new_target_file_content = []
30
- target_file_content.split("\n").each do |line|
31
- if /#{Regexp.escape(transform_hook)}\s*$/.match?(line)
32
-
33
- if add_before
34
- new_target_file_content << "#{line} #{add_before}"
35
- else
36
- unless options[:prepend]
37
- new_target_file_content << line
38
- end
39
- end
40
-
41
- # get leading whitespace.
42
- line =~ /^(\s*).*#{Regexp.escape(transform_hook)}.*/
43
- leading_whitespace = $1
44
- new_target_file_content << "#{leading_whitespace}#{" " if increase_indent}#{transformed_content}"
45
-
46
- new_target_file_content << "#{leading_whitespace}#{add_after}" if add_after
47
-
48
- if options[:prepend]
49
- new_target_file_content << line
50
- end
51
- else
52
- new_target_file_content << line
53
- end
54
- end
55
-
56
- puts "Updating '#{transformed_file_name}'."
57
-
58
- File.write(transformed_file_name, new_target_file_content.join("\n") + "\n")
59
- end
60
- end
61
-
62
11
  # filter out options.
63
12
  argv = []
64
13
  @options = {}
@@ -75,6 +24,11 @@ ARGV.each do |arg|
75
24
  end
76
25
  end
77
26
 
27
+ def standard_protip
28
+ puts "🏆 Protip: Commit your other changes before running Super Scaffolding so it's easy to undo if you (or we) make any mistakes."
29
+ puts "If you do that, you can reset to your last commit state by using `git checkout .` and `git clean -d -f` ."
30
+ end
31
+
78
32
  def check_required_options_for_attributes(scaffolding_type, attributes, child, parent = nil)
79
33
  attributes.each do |attribute|
80
34
  parts = attribute.split(":")
@@ -129,11 +83,9 @@ def show_usage
129
83
  puts ""
130
84
  puts "Supported types of scaffolding:"
131
85
  puts ""
132
- puts " crud"
133
- puts " crud-field"
134
- puts " join-model"
135
- puts " oauth-provider"
136
- puts " breadcrumbs"
86
+ BulletTrain::SuperScaffolding.scaffolders.each do |key, _|
87
+ puts " #{key}"
88
+ end
137
89
  puts ""
138
90
  puts "Try \`bin/super-scaffold [type]` for usage examples.".blue
139
91
  puts ""
@@ -142,394 +94,16 @@ end
142
94
  # grab the _type_ of scaffold we're doing.
143
95
  scaffolding_type = argv.shift
144
96
 
145
- # if we're doing the classic super scaffolding ..
146
- if scaffolding_type == "crud"
147
-
148
- unless argv.count >= 3
149
- puts ""
150
- puts "🚅 usage: bin/super-scaffold crud <Model> <ParentModel[s]> <attribute:type> <attribute:type> ..."
151
- puts ""
152
- puts "E.g. a Team has many Sites with some attributes:"
153
- puts " rails g model Site team:references name:string url:text"
154
- puts " bin/super-scaffold crud Site Team name:string url:text"
155
- puts ""
156
- puts "E.g. a Section belongs to a Page, which belongs to a Site, which belongs to a Team:"
157
- puts " rails g model Section page:references title:text body:text"
158
- puts " bin/super-scaffold crud Section Page,Site,Team title:text body:text"
159
- puts ""
160
- puts "E.g. an Image belongs to either a Page or a Site:"
161
- puts " Doable! See https://bit.ly/2NvO8El for a step by step guide."
162
- puts ""
163
- puts "E.g. Pages belong to a Site and are sortable via drag-and-drop:"
164
- puts " rails g model Page site:references name:string path:text"
165
- puts " bin/super-scaffold crud Page Site,Team name:text path:text --sortable"
166
- puts ""
167
- puts "🏆 Protip: Commit your other changes before running Super Scaffolding so it's easy to undo if you (or we) make any mistakes."
168
- puts "If you do that, you can reset to your last commit state by using `git checkout .` and `git clean -d -f` ."
169
- puts ""
170
- puts "Give it a shot! Let us know if you have any trouble with it! ✌️"
171
- puts ""
172
- exit
173
- end
174
-
175
- child = argv[0]
176
- parents = argv[1] ? argv[1].split(",") : []
177
- parents = parents.map(&:classify).uniq
178
- parent = parents.first
179
-
180
- unless parents.include?("Team")
181
- raise "Parents for #{child} should trace back to the Team model, but Team wasn't provided. Please confirm that all of the parents tracing back to the Team model are present and try again.\n" +
182
- "E.g.:\n" +
183
- "rails g model Section page:references title:text body:text\n" +
184
- "bin/super-scaffold crud Section Page,Site,Team title:text body:text\n"
185
- end
186
-
187
- # get all the attributes.
188
- attributes = argv[2..-1]
189
-
190
- check_required_options_for_attributes(scaffolding_type, attributes, child, parent)
191
-
192
- transformer = Scaffolding::Transformer.new(child, parents, @options)
193
- transformer.scaffold_crud(attributes)
194
-
195
- transformer.additional_steps.each_with_index do |additional_step, index|
196
- color, message = additional_step
197
- puts ""
198
- puts "#{index + 1}. #{message}".send(color)
199
- end
200
- puts ""
201
-
202
- elsif scaffolding_type == "crud-field"
203
-
204
- unless argv.count >= 2
205
- puts ""
206
- puts "🚅 usage: bin/super-scaffold crud-field <Model> <attribute:type> <attribute:type> ... [options]"
207
- puts ""
208
- puts "E.g. add a description and body to Pages:"
209
- puts " rails g migration add_description_etc_to_pages description:text body:text"
210
- puts " bin/super-scaffold crud-field Page description:text body:text"
211
- puts ""
212
- puts "Options:"
213
- puts ""
214
- puts " --skip-table: Only add to the new/edit form and show view."
215
- puts ""
216
- exit
217
- end
218
-
219
- # We pass this value to parents to create a new Scaffolding::Transformer because
220
- # we don't actually need knowledge of the parent to add the new field.
221
- parents = [""]
222
- child = argv[0]
223
-
224
- # get all the attributes.
225
- attributes = argv[1..-1]
226
-
227
- check_required_options_for_attributes(scaffolding_type, attributes, child)
228
-
229
- transformer = Scaffolding::Transformer.new(child, parents, @options)
230
- transformer.add_attributes_to_various_views(attributes, type: :crud_field)
231
-
232
- transformer.additional_steps.uniq.each_with_index do |additional_step, index|
233
- color, message = additional_step
234
- puts ""
235
- puts "#{index + 1}. #{message}".send(color)
236
- end
237
- puts ""
238
-
239
- elsif scaffolding_type == "join-model"
240
-
241
- unless argv.count >= 3
242
- puts ""
243
- puts "🚅 usage: bin/super-scaffold join-model <JoinModel> <left_association> <right_association>"
244
- puts ""
245
- puts "E.g. Add project-specific tags to a project:"
246
- puts ""
247
- puts " Given the following example models:".blue
248
- puts ""
249
- puts " rails g model Project team:references name:string description:text"
250
- puts " bin/super-scaffold crud Project Team name:text_field description:trix_editor"
251
- puts ""
252
- puts " rails g model Projects::Tag team:references name:string"
253
- puts " bin/super-scaffold crud Projects::Tag Team name:text_field"
254
- puts ""
255
- puts " 1️⃣ Use the standard Rails model generator to generate the join model:".blue
256
- puts ""
257
- puts " rails g model Projects::AppliedTag project:references tag:references"
258
- puts ""
259
- puts " 👋 Don't run migrations yet! Sometimes Super Scaffolding updates them for you.".yellow
260
- puts ""
261
- puts " 2️⃣ Use `join-model` scaffolding to prepare the join model for use in `crud-field` scaffolding:".blue
262
- puts ""
263
- puts " bin/super-scaffold join-model Projects::AppliedTag project_id[class_name=Project] tag_id[class_name=Projects::Tag]"
264
- puts ""
265
- puts " 3️⃣ Now you can use `crud-field` scaffolding to actually add the field to the form of the parent model:".blue
266
- puts ""
267
- puts " bin/super-scaffold crud-field Project tag_ids:super_select[class_name=Projects::Tag]"
268
- puts ""
269
- puts " 👋 Heads up! There will be one follow-up step output by this command that you need to take action on."
270
- puts ""
271
- puts " 4️⃣ Now you can run your migrations.".blue
272
- exit
273
- end
274
-
275
- child = argv[0]
276
- primary_parent = argv[1].split("class_name=").last.split(",").first.split("]").first
277
- secondary_parent = argv[2].split("class_name=").last.split(",").first.split("]").first
278
-
279
- # There should only be two attributes.
280
- attributes = [argv[1], argv[2]]
281
-
282
- # Pretend we're doing a `super_select` scaffolding because it will do the correct thing.
283
- attributes = attributes.map { |attribute| attribute.gsub("\[", ":super_select\[") }
284
- attributes = attributes.map { |attribute| attribute.gsub("\]", ",required\]") }
285
-
286
- transformer = Scaffolding::Transformer.new(child, [primary_parent], @options)
287
-
288
- # We need this transformer to reflect on the class names _just_ between e.g. `Project` and `Projects::Tag`, without the join model.
289
- has_many_through_transformer = Scaffolding::Transformer.new(secondary_parent, [primary_parent], @options)
290
-
291
- # We need this transformer to reflect on the association between `Projects::Tag` and `Projects::AppliedTag` backwards.
292
- inverse_transformer = Scaffolding::Transformer.new(child, [secondary_parent], @options)
293
-
294
- # We need this transformer to reflect on the class names _just_ between e.g. `Projects::Tag` and `Project`, without the join model.
295
- inverse_has_many_through_transformer = Scaffolding::Transformer.new(primary_parent, [secondary_parent], @options)
296
-
297
- # However, for the first attribute, we actually don't need the scope validator (and can't really implement it).
298
- attributes[0] = attributes[0].gsub("\]", ",unscoped\]")
299
-
300
- has_many_through_association = has_many_through_transformer.transform_string("completely_concrete_tangible_things")
301
- source = transformer.transform_string("absolutely_abstract_creative_concept.valid_$HAS_MANY_THROUGH_ASSOCIATION")
302
- source.gsub!("$HAS_MANY_THROUGH_ASSOCIATION", has_many_through_association)
303
-
304
- # For the second one, we don't want users to have to define the list of valid options in the join model, so we do this:
305
- attributes[1] = attributes[1].gsub("\]", ",source=#{source}\]")
306
-
307
- # This model hasn't been crud scaffolded, so a bunch of views are skipped here, but that's OK!
308
- # It does what we need on the files that exist.
309
- transformer.add_scaffolding_hooks_to_model
310
-
311
- transformer.suppress_could_not_find = true
312
- transformer.add_attributes_to_various_views(attributes, type: :crud_field)
313
- transformer.suppress_could_not_find = false
314
-
315
- # Add the `has_many ... through:` association in both directions.
316
- transformer.add_has_many_through_associations(has_many_through_transformer)
317
- inverse_transformer.add_has_many_through_associations(inverse_has_many_through_transformer)
318
-
319
- additional_steps = (transformer.additional_steps + has_many_through_transformer.additional_steps + inverse_transformer.additional_steps + inverse_has_many_through_transformer.additional_steps).uniq
320
-
321
- additional_steps.each_with_index do |additional_step, index|
322
- color, message = additional_step
323
- puts ""
324
- puts "#{index + 1}. #{message}".send(color)
325
- end
326
- puts ""
327
-
328
- elsif scaffolding_type == "breadcrumbs"
329
-
330
- unless argv.count == 2
331
- puts ""
332
- puts "🚅 usage: bin/super-scaffold breadcrumbs <Model> <ParentModel[s]>"
333
- puts ""
334
- puts "Heads up! You only need to use this if you generated your views before the new Bullet Train breadcrumbs implementation came into effect.".green
335
- puts ""
336
- puts "E.g. create updated breadcrumbs for Pages:"
337
- puts " bin/super-scaffold breadcrumbs Page Site,Team"
338
- puts ""
339
- puts "When Super Scaffolding breadcrumbs, you have to specify the entire path of the immediate parent back to Team."
340
- puts ""
341
- exit
342
- end
343
-
344
- child = argv[0]
345
- parents = argv[1] ? argv[1].split(",") : []
346
- parents = parents.map(&:classify).uniq
347
- parent = parents.first
348
-
349
- unless parents.include?("Team")
350
- raise "Parents for #{child} should trace back to the Team model, but Team wasn't provided. Please confirm that all of the parents tracing back to the Team model are present and try again.\n" +
351
- "E.g.:\n" +
352
- "bin/super-scaffold breadcrumbs Page Site,Team\n"
353
- end
354
-
355
- # get all the attributes.
356
- transformer = Scaffolding::Transformer.new(child, parents, @options)
357
- transformer.scaffold_new_breadcrumbs(child, parents)
358
-
359
- elsif scaffolding_type == "oauth-provider"
360
-
361
- unless argv.count >= 5
362
- puts ""
363
- puts "🚅 usage: bin/super-scaffold oauth-provider <omniauth_gem> <gems_provider_name> <our_provider_name> <PROVIDER_API_KEY_IN_ENV> <PROVIDER_API_SECRET_IN_ENV> [options]"
364
- puts ""
365
- puts "E.g. what we'd do to start Stripe off (if we didn't already do it):"
366
- puts " bin/super-scaffold oauth-provider omniauth-stripe-connect stripe_connect Oauth::StripeAccount STRIPE_CLIENT_ID STRIPE_SECRET_KEY --icon=ti-money"
367
- puts ""
368
- puts "E.g. what we actually did to start Shopify off:"
369
- puts " bin/super-scaffold oauth-provider omniauth-shopify-oauth2 shopify Oauth::ShopifyAccount SHOPIFY_API_KEY SHOPIFY_API_SECRET_KEY --icon=ti-shopping-cart"
370
- puts ""
371
- puts "Options:"
372
- puts ""
373
- puts " --icon={ti-*}: Specify an icon."
374
- puts ""
375
- puts "For a list of readily available provider strategies, see https://github.com/omniauth/omniauth/wiki/List-of-Strategies ."
376
- puts ""
377
- exit
378
- end
379
-
380
- _, omniauth_gem, gems_provider_name, our_provider_name, api_key, api_secret = *ARGV
381
-
382
- unless match = our_provider_name.match(/Oauth::(.*)Account/)
383
- puts "\n🚨 Your provider name must match the pattern of `Oauth::{Name}Account`, e.g. `Oauth::StripeAccount`\n".red
384
- return
385
- end
386
-
387
- options = {
388
- omniauth_gem: omniauth_gem,
389
- gems_provider_name: gems_provider_name,
390
- our_provider_name: match[1],
391
- api_key: api_key,
392
- api_secret: api_secret
393
- }
394
-
395
- unless File.exist?(oauth_transform_string("./app/models/oauth/stripe_account.rb", options)) &&
396
- File.exist?(oauth_transform_string("./app/models/integrations/stripe_installation.rb", options)) &&
397
- File.exist?(oauth_transform_string("./app/models/webhooks/incoming/oauth/stripe_account_webhook.rb", options))
398
- puts ""
399
- puts oauth_transform_string("🚨 Before doing the actual Super Scaffolding, you'll need to generate the models like so:", options).red
400
- puts ""
401
- puts oauth_transform_string(" rails g model Oauth::StripeAccount uid:string data:jsonb user:references", options).red
402
- puts oauth_transform_string(" rails g model Integrations::StripeInstallation team:references oauth_stripe_account:references name:string", options).red
403
- puts oauth_transform_string(" rails g model Webhooks::Incoming::Oauth::StripeAccountWebhook data:jsonb processed_at:datetime verified_at:datetime oauth_stripe_account:references", options).red
404
- puts ""
405
- puts "However, don't do the `rake db:migrate` until after you re-run Super Scaffolding, as it will need to update some settings in those migrations.".red
406
- puts ""
407
- return
408
- end
409
-
410
- icon_name = nil
411
- if @options["icon"].present?
412
- icon_name = @options["icon"]
413
- else
414
- puts "OK, great! Let's do this! By default providers will appear with a dollar symbol,"
415
- puts "but after you hit enter I'll open a page where you can view other icon options."
416
- puts "When you find one you like, hover your mouse over it and then come back here and"
417
- puts "and enter the name of the icon you want to use."
418
- response = STDIN.gets.chomp
419
- `open http://light.pinsupreme.com/icon_fonts_themefy.html`
420
- puts ""
421
- puts "Did you find an icon you wanted to use? Enter the name here or hit enter to just"
422
- puts "use the dollar symbol:"
423
- icon_name = STDIN.gets.chomp
424
- puts ""
425
- unless icon_name.length > 0 || icon_name.downcase == "y"
426
- icon_name = "icon-puzzle"
427
- end
428
- end
429
-
430
- options[:icon] = icon_name
431
-
432
- [
433
-
434
- # User OAuth.
435
- "./app/models/oauth/stripe_account.rb",
436
- "./app/models/webhooks/incoming/oauth/stripe_account_webhook.rb",
437
- "./app/controllers/account/oauth/stripe_accounts_controller.rb",
438
- "./app/controllers/webhooks/incoming/oauth/stripe_account_webhooks_controller.rb",
439
- "./app/views/account/oauth/stripe_accounts",
440
- "./test/models/oauth/stripe_account_test.rb",
441
- "./test/factories/oauth/stripe_accounts.rb",
442
- "./config/locales/en/oauth/stripe_accounts.en.yml",
443
- "./app/views/devise/shared/oauth/_stripe.html.erb",
444
-
445
- # Team Integration.
446
- "./app/models/integrations/stripe_installation.rb",
447
- # './app/serializers/api/v1/integrations/stripe_installation_serializer.rb',
448
- "./app/controllers/account/integrations/stripe_installations_controller.rb",
449
- "./app/views/account/integrations/stripe_installations",
450
- "./test/models/integrations/stripe_installation_test.rb",
451
- "./test/factories/integrations/stripe_installations.rb",
452
- "./config/locales/en/integrations/stripe_installations.en.yml",
453
-
454
- # Webhook.
455
- "./app/models/webhooks/incoming/oauth/stripe_account_webhook.rb",
456
- "./app/controllers/webhooks/incoming/oauth/stripe_account_webhooks_controller.rb"
457
-
458
- ].each do |name|
459
- if File.directory?(name)
460
- oauth_scaffold_directory(name, options)
461
- else
462
- oauth_scaffold_file(name, options)
463
- end
464
- end
465
-
466
- oauth_scaffold_add_line_to_file("./app/views/devise/shared/_oauth.html.erb", "<%= render 'devise/shared/oauth/stripe', verb: verb if stripe_enabled? %>", "<%# 🚅 super scaffolding will insert new oauth providers above this line. %>", options, prepend: true)
467
- oauth_scaffold_add_line_to_file("./app/views/account/users/edit.html.erb", "<%= render 'account/oauth/stripe_accounts/index', context: @user, stripe_accounts: @user.oauth_stripe_accounts if stripe_enabled? %>", "<% # 🚅 super scaffolding will insert new oauth providers above this line. %>", options, prepend: true)
468
- oauth_scaffold_add_line_to_file("./config/initializers/devise.rb", "config.omniauth :stripe_connect, ENV['STRIPE_CLIENT_ID'], ENV['STRIPE_SECRET_KEY'], {\n ## specify options for your oauth provider here, e.g.:\n # scope: 'read_products,read_orders,write_content',\n }\n", "# 🚅 super scaffolding will insert new oauth providers above this line.", options, prepend: true)
469
- oauth_scaffold_add_line_to_file("./app/controllers/account/oauth/omniauth_callbacks_controller.rb", "def stripe_connect\n callback(\"Stripe\", team_id_from_env)\n end\n", "# 🚅 super scaffolding will insert new oauth providers above this line.", options, prepend: true)
470
- oauth_scaffold_add_line_to_file("./app/models/team.rb", "has_many :integrations_stripe_installations, class_name: 'Integrations::StripeInstallation', dependent: :destroy if stripe_enabled?", "# 🚅 add oauth providers above.", options, prepend: true)
471
- oauth_scaffold_add_line_to_file("./app/models/user.rb", "has_many :oauth_stripe_accounts, class_name: 'Oauth::StripeAccount' if stripe_enabled?", "# 🚅 add oauth providers above.", options, prepend: true)
472
- oauth_scaffold_add_line_to_file("./config/locales/en/oauth.en.yml", "stripe_connect: Stripe", "# 🚅 super scaffolding will insert new oauth providers above this line.", options, prepend: true)
473
- oauth_scaffold_add_line_to_file("./app/views/account/shared/_menu.html.erb", "<%= render 'account/integrations/stripe_installations/menu_item' if stripe_enabled? %>", "<%# 🚅 super scaffolding will insert new oauth providers above this line. %>", options, prepend: true)
474
- oauth_scaffold_add_line_to_file("./config/routes.rb", "resources :stripe_account_webhooks if stripe_enabled?", "# 🚅 super scaffolding will insert new oauth provider webhooks above this line.", options, prepend: true)
475
- oauth_scaffold_add_line_to_file("./config/routes.rb", "resources :stripe_accounts if stripe_enabled?", "# 🚅 super scaffolding will insert new oauth providers above this line.", options, prepend: true)
476
- oauth_scaffold_add_line_to_file("./config/routes.rb", "resources :stripe_installations if stripe_enabled?", "# 🚅 super scaffolding will insert new integration installations above this line.", options, prepend: true)
477
- oauth_scaffold_add_line_to_file("./Gemfile", "gem 'omniauth-stripe-connect'", "# 🚅 super scaffolding will insert new oauth providers above this line.", options, prepend: true)
478
- oauth_scaffold_add_line_to_file("./lib/bullet_train.rb", "def stripe_enabled?\n ENV['STRIPE_CLIENT_ID'].present? && ENV['STRIPE_SECRET_KEY'].present?\nend\n", "# 🚅 super scaffolding will insert new oauth providers above this line.", options, prepend: true)
479
- oauth_scaffold_add_line_to_file("./lib/bullet_train.rb", "stripe_enabled?,", "# 🚅 super scaffolding will insert new oauth provider checks above this line.", options, prepend: true)
480
- oauth_scaffold_add_line_to_file("./app/models/ability.rb", "if stripe_enabled?
481
- can [:read, :create, :destroy], Oauth::StripeAccount, user_id: user.id
482
- can :manage, Integrations::StripeInstallation, team_id: user.team_ids
483
- can :destroy, Integrations::StripeInstallation, oauth_stripe_account: {user_id: user.id}
484
- end
485
- ", "# 🚅 super scaffolding will insert any new oauth providers above.", options, prepend: true)
486
-
487
- # find the database migration that defines this relationship.
488
- migration_file_name = `grep "create_table #{oauth_transform_string(":oauth_stripe_accounts", options)}" db/migrate/*`.split(":").first
489
- legacy_replace_in_file(migration_file_name, "null: false", "null: true")
490
-
491
- migration_file_name = `grep "create_table #{oauth_transform_string(":integrations_stripe_installations", options)}" db/migrate/*`.split(":").first
492
- legacy_replace_in_file(migration_file_name,
493
- oauth_transform_string("t.references :oauth_stripe_account, null: false, foreign_key: true", options),
494
- oauth_transform_string('t.references :oauth_stripe_account, null: false, foreign_key: true, index: {name: "index_stripe_installations_on_oauth_stripe_account_id"}', options))
495
-
496
- migration_file_name = `grep "create_table #{oauth_transform_string(":webhooks_incoming_oauth_stripe_account_webhooks", options)}" db/migrate/*`.split(":").first
497
- legacy_replace_in_file(migration_file_name, "null: false", "null: true")
498
- legacy_replace_in_file(migration_file_name, "foreign_key: true", 'foreign_key: true, index: {name: "index_stripe_webhooks_on_oauth_stripe_account_id"}')
499
-
500
- puts ""
501
- puts "🎉"
502
- puts ""
503
- puts "You'll probably need to `bundle install`.".green
504
- puts ""
505
- puts "If the OAuth provider asks you for some whitelisted callback URLs, the URL structure for those is as so:"
506
- puts ""
507
- path = "users/auth/stripe_connect/callback"
508
- puts oauth_transform_string(" https://yourdomain.co/#{path}", options)
509
- puts oauth_transform_string(" https://yourtunnel.ngrok.io/#{path}", options)
510
- puts oauth_transform_string(" http://localhost:3000/#{path}", options)
511
- puts ""
512
- puts "If you're able to specify an endpoint to receive webhooks from this provider, use this URL:"
513
- puts ""
514
- path = "webhooks/incoming/oauth/stripe_account_webhooks"
515
- puts oauth_transform_string(" https://yourdomain.co/#{path}", options)
516
- puts oauth_transform_string(" https://yourtunnel.ngrok.io/#{path}", options)
517
- puts oauth_transform_string(" http://localhost:3000/#{path}", options)
518
- puts ""
519
- puts ""
520
- puts "If you'd like to edit how your Bullet Train application refers to this provider, just edit the locale file at `config/locales/en/oauth.en.yml`."
521
- puts ""
522
- puts "And finally, if you need to specify any custom authorizations or options for your OAuth integration with this provider, you can configure those in `config/initializers/devise.rb`."
523
- puts ""
524
-
97
+ if BulletTrain::SuperScaffolding.scaffolders.include?(scaffolding_type)
98
+ scaffolder = BulletTrain::SuperScaffolding.scaffolders[scaffolding_type].constantize
99
+ scaffolder.new(argv, @options).run
525
100
  elsif argv.count > 1
526
-
527
101
  puts ""
528
102
  puts "👋"
529
103
  puts "The command line options for Super Scaffolding have changed slightly:".yellow
530
104
  puts "To use the original Super Scaffolding that you know and love, use the `crud` option.".yellow
531
- show_usage
532
105
 
106
+ show_usage
533
107
  else
534
108
  if ARGV.first.present?
535
109
  puts ""
data/lib/scaffolding.rb CHANGED
@@ -1,7 +1,2 @@
1
1
  module Scaffolding
2
2
  end
3
-
4
- require_relative "scaffolding/oauth_providers"
5
- require_relative "scaffolding/transformer"
6
- require_relative "scaffolding/class_names_transformer"
7
- require_relative "scaffolding/routes_file_manipulator"
@@ -1,6 +1,12 @@
1
1
  namespace :bullet_train do
2
2
  desc "Next-level code generation"
3
- task :super_scaffolding => :environment do
3
+ task :super_scaffolding, [:all_options] => :environment do |t, arguments|
4
+ ARGV.pop while ARGV.any?
5
+
6
+ arguments[:all_options]&.split&.each do |argument|
7
+ ARGV.push(argument)
8
+ end
9
+
4
10
  BulletTrain::SuperScaffolding::Runner.new.run
5
11
  end
6
12
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bullet_train-super_scaffolding
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Culver
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-02-01 00:00:00.000000000 Z
11
+ date: 2022-02-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 7.0.0
19
+ version: 6.0.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 7.0.0
26
+ version: 6.0.0
27
27
  description: Bullet Train Super Scaffolding
28
28
  email:
29
29
  - andrew.culver@gmail.com
@@ -38,8 +38,14 @@ files:
38
38
  - config/routes.rb
39
39
  - lib/bullet_train/super_scaffolding.rb
40
40
  - lib/bullet_train/super_scaffolding/engine.rb
41
+ - lib/bullet_train/super_scaffolding/scaffolder.rb
42
+ - lib/bullet_train/super_scaffolding/scaffolders/crud_field_scaffolder.rb
43
+ - lib/bullet_train/super_scaffolding/scaffolders/crud_scaffolder.rb
44
+ - lib/bullet_train/super_scaffolding/scaffolders/join_model_scaffolder.rb
45
+ - lib/bullet_train/super_scaffolding/scaffolders/oauth_provider_scaffolder.rb
41
46
  - lib/bullet_train/super_scaffolding/version.rb
42
47
  - lib/scaffolding.rb
48
+ - lib/scaffolding/block_manipulator.rb
43
49
  - lib/scaffolding/class_names_transformer.rb
44
50
  - lib/scaffolding/oauth_providers.rb
45
51
  - lib/scaffolding/routes_file_manipulator.rb