bullet_train-super_scaffolding 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,543 @@
1
+ require "active_support/inflector"
2
+ require "fileutils"
3
+ require "pry"
4
+ require "colorize"
5
+
6
+ require_relative "#{APP_ROOT}/config/initializers/inflections"
7
+
8
+ # TODO these methods were removed from the global scope in super scaffolding and moved to `Scaffolding::Transformer`,
9
+ # but oauth provider scaffolding hasn't been updated yet.
10
+
11
+ def legacy_replace_in_file(file, before, after)
12
+ puts "Replacing in '#{file}'."
13
+ target_file_content = File.read(file)
14
+ target_file_content.gsub!(before, after)
15
+ File.write(file, target_file_content)
16
+ end
17
+
18
+ def legacy_add_line_to_file(file, content, hook, child, parent, options = {})
19
+ increase_indent = options[:increase_indent]
20
+ add_before = options[:add_before]
21
+ add_after = options[:add_after]
22
+
23
+ transformed_file_name = file
24
+ transformed_content = content
25
+ transform_hook = hook
26
+
27
+ target_file_content = File.read(transformed_file_name)
28
+
29
+ if target_file_content.include?(transformed_content)
30
+ puts "No need to update '#{transformed_file_name}'. It already has '#{transformed_content}'."
31
+ else
32
+ new_target_file_content = []
33
+ target_file_content.split("\n").each do |line|
34
+ if /#{Regexp.escape(transform_hook)}\s*$/.match?(line)
35
+
36
+ if add_before
37
+ new_target_file_content << "#{line} #{add_before}"
38
+ else
39
+ unless options[:prepend]
40
+ new_target_file_content << line
41
+ end
42
+ end
43
+
44
+ # get leading whitespace.
45
+ line =~ /^(\s*).*#{Regexp.escape(transform_hook)}.*/
46
+ leading_whitespace = $1
47
+ new_target_file_content << "#{leading_whitespace}#{" " if increase_indent}#{transformed_content}"
48
+
49
+ new_target_file_content << "#{leading_whitespace}#{add_after}" if add_after
50
+
51
+ if options[:prepend]
52
+ new_target_file_content << line
53
+ end
54
+ else
55
+ new_target_file_content << line
56
+ end
57
+ end
58
+
59
+ puts "Updating '#{transformed_file_name}'."
60
+
61
+ File.write(transformed_file_name, new_target_file_content.join("\n") + "\n")
62
+ end
63
+ end
64
+
65
+ # filter out options.
66
+ argv = []
67
+ @options = {}
68
+ ARGV.each do |arg|
69
+ if arg[0..1] == "--"
70
+ arg = arg[2..-1]
71
+ if arg.split("=").count > 1
72
+ @options[arg.split("=")[0]] = arg.split("=")[1]
73
+ else
74
+ @options[arg] = true
75
+ end
76
+ else
77
+ argv << arg
78
+ end
79
+ end
80
+
81
+ def check_required_options_for_attributes(scaffolding_type, attributes, child, parent = nil)
82
+ attributes.each do |attribute|
83
+ parts = attribute.split(":")
84
+ name = parts.shift
85
+ type = parts.join(":")
86
+
87
+ # extract any options they passed in with the field.
88
+ type, attribute_options = type.scan(/^(.*)\[(.*)\]/).first || type
89
+
90
+ # create a hash of the options.
91
+ attribute_options = if attribute_options
92
+ attribute_options.split(",").map do |s|
93
+ option_name, option_value = s.split("=")
94
+ [option_name.to_sym, option_value || true]
95
+ end.to_h
96
+ else
97
+ {}
98
+ end
99
+
100
+ if name.match?(/_id$/) || name.match?(/_ids$/)
101
+ attribute_options ||= {}
102
+ unless attribute_options[:vanilla]
103
+ name_without_id = if name.match?(/_id$/)
104
+ name.gsub(/_id$/, "")
105
+ elsif name.match?(/_ids$/)
106
+ name.gsub(/_ids$/, "")
107
+ end
108
+
109
+ attribute_options[:class_name] ||= name_without_id.classify
110
+
111
+ file_name = "app/models/#{attribute_options[:class_name].underscore}.rb"
112
+ unless File.exist?(file_name)
113
+ puts ""
114
+ puts "Attributes that end with `_id` or `_ids` trigger awesome, powerful magic in Super Scaffolding. However, because no `#{attribute_options[:class_name]}` class was found defined in `#{file_name}`, you'll need to specify a `class_name` that exists to let us know what model class is on the other side of the association, like so:".red
115
+ puts ""
116
+ puts " bin/super-scaffold #{scaffolding_type} #{child}#{" " + parent if parent.present?} #{name}:#{type}[class_name=#{name.gsub(/_ids?$/, "").classify}]".red
117
+ puts ""
118
+ puts "If `#{name}` is just a regular field and isn't backed by an ActiveRecord association, you can skip all this with the `[vanilla]` option, e.g.:".red
119
+ puts ""
120
+ puts " bin/super-scaffold #{scaffolding_type} #{child}#{" " + parent if parent.present?} #{name}:#{type}[vanilla]".red
121
+ puts ""
122
+ exit
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
128
+
129
+ def show_usage
130
+ puts ""
131
+ puts "🚅 usage: bin/super-scaffold [type] (... | --help)"
132
+ puts ""
133
+ puts "Supported types of scaffolding:"
134
+ puts ""
135
+ puts " crud"
136
+ puts " crud-field"
137
+ puts " join-model"
138
+ puts " oauth-provider"
139
+ puts " breadcrumbs"
140
+ puts ""
141
+ puts "Try \`bin/super-scaffold [type]` for usage examples.".blue
142
+ puts ""
143
+ end
144
+
145
+ # grab the _type_ of scaffold we're doing.
146
+ scaffolding_type = argv.shift
147
+
148
+ # if we're doing the classic super scaffolding ..
149
+ if scaffolding_type == "crud"
150
+
151
+ unless argv.count >= 3
152
+ puts ""
153
+ puts "🚅 usage: bin/super-scaffold crud <Model> <ParentModel[s]> <attribute:type> <attribute:type> ..."
154
+ puts ""
155
+ puts "E.g. a Team has many Sites with some attributes:"
156
+ puts " rails g model Site team:references name:string url:text"
157
+ puts " bin/super-scaffold crud Site Team name:string url:text"
158
+ puts ""
159
+ puts "E.g. a Section belongs to a Page, which belongs to a Site, which belongs to a Team:"
160
+ puts " rails g model Section page:references title:text body:text"
161
+ puts " bin/super-scaffold crud Section Page,Site,Team title:text body:text"
162
+ puts ""
163
+ puts "E.g. an Image belongs to either a Page or a Site:"
164
+ puts " Doable! See https://bit.ly/2NvO8El for a step by step guide."
165
+ puts ""
166
+ puts "E.g. Pages belong to a Site and are sortable via drag-and-drop:"
167
+ puts " rails g model Page site:references name:string path:text"
168
+ puts " bin/super-scaffold crud Page Site,Team name:text path:text --sortable"
169
+ puts ""
170
+ puts "🏆 Protip: Commit your other changes before running Super Scaffolding so it's easy to undo if you (or we) make any mistakes."
171
+ puts "If you do that, you can reset to your last commit state by using `git checkout .` and `git clean -d -f` ."
172
+ puts ""
173
+ puts "Give it a shot! Let us know if you have any trouble with it! ✌️"
174
+ puts ""
175
+ exit
176
+ end
177
+
178
+ child = argv[0]
179
+ parents = argv[1] ? argv[1].split(",") : []
180
+ parents = parents.map(&:classify).uniq
181
+ parent = parents.first
182
+
183
+ unless parents.include?("Team")
184
+ 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" +
185
+ "E.g.:\n" +
186
+ "rails g model Section page:references title:text body:text\n" +
187
+ "bin/super-scaffold crud Section Page,Site,Team title:text body:text\n"
188
+ end
189
+
190
+ # get all the attributes.
191
+ attributes = argv[2..-1]
192
+
193
+ check_required_options_for_attributes(scaffolding_type, attributes, child, parent)
194
+
195
+ transformer = Scaffolding::Transformer.new(child, parents, @options)
196
+ transformer.scaffold_crud(attributes)
197
+
198
+ transformer.additional_steps.each_with_index do |additional_step, index|
199
+ color, message = additional_step
200
+ puts ""
201
+ puts "#{index + 1}. #{message}".send(color)
202
+ end
203
+ puts ""
204
+
205
+ elsif scaffolding_type == "crud-field"
206
+
207
+ unless argv.count >= 2
208
+ puts ""
209
+ puts "🚅 usage: bin/super-scaffold crud-field <Model> <attribute:type> <attribute:type> ... [options]"
210
+ puts ""
211
+ puts "E.g. add a description and body to Pages:"
212
+ puts " rails g migration add_description_etc_to_pages description:text body:text"
213
+ puts " bin/super-scaffold crud-field Page description:text body:text"
214
+ puts ""
215
+ puts "Options:"
216
+ puts ""
217
+ puts " --skip-table: Only add to the new/edit form and show view."
218
+ puts ""
219
+ exit
220
+ end
221
+
222
+ # We pass this value to parents to create a new Scaffolding::Transformer because
223
+ # we don't actually need knowledge of the parent to add the new field.
224
+ parents = [""]
225
+ child = argv[0]
226
+
227
+ # get all the attributes.
228
+ attributes = argv[1..-1]
229
+
230
+ check_required_options_for_attributes(scaffolding_type, attributes, child)
231
+
232
+ transformer = Scaffolding::Transformer.new(child, parents, @options)
233
+ transformer.add_attributes_to_various_views(attributes, type: :crud_field)
234
+
235
+ transformer.additional_steps.uniq.each_with_index do |additional_step, index|
236
+ color, message = additional_step
237
+ puts ""
238
+ puts "#{index + 1}. #{message}".send(color)
239
+ end
240
+ puts ""
241
+
242
+ elsif scaffolding_type == "join-model"
243
+
244
+ unless argv.count >= 3
245
+ puts ""
246
+ puts "🚅 usage: bin/super-scaffold join-model <JoinModel> <left_association> <right_association>"
247
+ puts ""
248
+ puts "E.g. Add project-specific tags to a project:"
249
+ puts ""
250
+ puts " Given the following example models:".blue
251
+ puts ""
252
+ puts " rails g model Project team:references name:string description:text"
253
+ puts " bin/super-scaffold crud Project Team name:text_field description:trix_editor"
254
+ puts ""
255
+ puts " rails g model Projects::Tag team:references name:string"
256
+ puts " bin/super-scaffold crud Projects::Tag Team name:text_field"
257
+ puts ""
258
+ puts " 1️⃣ Use the standard Rails model generator to generate the join model:".blue
259
+ puts ""
260
+ puts " rails g model Projects::AppliedTag project:references tag:references"
261
+ puts ""
262
+ puts " 👋 Don't run migrations yet! Sometimes Super Scaffolding updates them for you.".yellow
263
+ puts ""
264
+ puts " 2️⃣ Use `join-model` scaffolding to prepare the join model for use in `crud-field` scaffolding:".blue
265
+ puts ""
266
+ puts " bin/super-scaffold join-model Projects::AppliedTag project_id[class_name=Project] tag_id[class_name=Projects::Tag]"
267
+ puts ""
268
+ puts " 3️⃣ Now you can use `crud-field` scaffolding to actually add the field to the form of the parent model:".blue
269
+ puts ""
270
+ puts " bin/super-scaffold crud-field Project tag_ids:super_select[class_name=Projects::Tag]"
271
+ puts ""
272
+ puts " 👋 Heads up! There will be one follow-up step output by this command that you need to take action on."
273
+ puts ""
274
+ puts " 4️⃣ Now you can run your migrations.".blue
275
+ exit
276
+ end
277
+
278
+ child = argv[0]
279
+ primary_parent = argv[1].split("class_name=").last.split(",").first.split("]").first
280
+ secondary_parent = argv[2].split("class_name=").last.split(",").first.split("]").first
281
+
282
+ # There should only be two attributes.
283
+ attributes = [argv[1], argv[2]]
284
+
285
+ # Pretend we're doing a `super_select` scaffolding because it will do the correct thing.
286
+ attributes = attributes.map { |attribute| attribute.gsub("\[", ":super_select\[") }
287
+ attributes = attributes.map { |attribute| attribute.gsub("\]", ",required\]") }
288
+
289
+ transformer = Scaffolding::Transformer.new(child, [primary_parent], @options)
290
+
291
+ # We need this transformer to reflect on the class names _just_ between e.g. `Project` and `Projects::Tag`, without the join model.
292
+ has_many_through_transformer = Scaffolding::Transformer.new(secondary_parent, [primary_parent], @options)
293
+
294
+ # We need this transformer to reflect on the association between `Projects::Tag` and `Projects::AppliedTag` backwards.
295
+ inverse_transformer = Scaffolding::Transformer.new(child, [secondary_parent], @options)
296
+
297
+ # We need this transformer to reflect on the class names _just_ between e.g. `Projects::Tag` and `Project`, without the join model.
298
+ inverse_has_many_through_transformer = Scaffolding::Transformer.new(primary_parent, [secondary_parent], @options)
299
+
300
+ # However, for the first attribute, we actually don't need the scope validator (and can't really implement it).
301
+ attributes[0] = attributes[0].gsub("\]", ",unscoped\]")
302
+
303
+ has_many_through_association = has_many_through_transformer.transform_string("completely_concrete_tangible_things")
304
+ source = transformer.transform_string("absolutely_abstract_creative_concept.valid_$HAS_MANY_THROUGH_ASSOCIATION")
305
+ source.gsub!("$HAS_MANY_THROUGH_ASSOCIATION", has_many_through_association)
306
+
307
+ # 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:
308
+ attributes[1] = attributes[1].gsub("\]", ",source=#{source}\]")
309
+
310
+ # This model hasn't been crud scaffolded, so a bunch of views are skipped here, but that's OK!
311
+ # It does what we need on the files that exist.
312
+ transformer.add_scaffolding_hooks_to_model
313
+
314
+ transformer.suppress_could_not_find = true
315
+ transformer.add_attributes_to_various_views(attributes, type: :crud_field)
316
+ transformer.suppress_could_not_find = false
317
+
318
+ # Add the `has_many ... through:` association in both directions.
319
+ transformer.add_has_many_through_associations(has_many_through_transformer)
320
+ inverse_transformer.add_has_many_through_associations(inverse_has_many_through_transformer)
321
+
322
+ additional_steps = (transformer.additional_steps + has_many_through_transformer.additional_steps + inverse_transformer.additional_steps + inverse_has_many_through_transformer.additional_steps).uniq
323
+
324
+ additional_steps.each_with_index do |additional_step, index|
325
+ color, message = additional_step
326
+ puts ""
327
+ puts "#{index + 1}. #{message}".send(color)
328
+ end
329
+ puts ""
330
+
331
+ elsif scaffolding_type == "breadcrumbs"
332
+
333
+ unless argv.count == 2
334
+ puts ""
335
+ puts "🚅 usage: bin/super-scaffold breadcrumbs <Model> <ParentModel[s]>"
336
+ puts ""
337
+ 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
338
+ puts ""
339
+ puts "E.g. create updated breadcrumbs for Pages:"
340
+ puts " bin/super-scaffold breadcrumbs Page Site,Team"
341
+ puts ""
342
+ puts "When Super Scaffolding breadcrumbs, you have to specify the entire path of the immediate parent back to Team."
343
+ puts ""
344
+ exit
345
+ end
346
+
347
+ child = argv[0]
348
+ parents = argv[1] ? argv[1].split(",") : []
349
+ parents = parents.map(&:classify).uniq
350
+ parent = parents.first
351
+
352
+ unless parents.include?("Team")
353
+ 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" +
354
+ "E.g.:\n" +
355
+ "bin/super-scaffold breadcrumbs Page Site,Team\n"
356
+ end
357
+
358
+ # get all the attributes.
359
+ transformer = Scaffolding::Transformer.new(child, parents, @options)
360
+ transformer.scaffold_new_breadcrumbs(child, parents)
361
+
362
+ elsif scaffolding_type == "oauth-provider"
363
+
364
+ unless argv.count >= 5
365
+ puts ""
366
+ 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]"
367
+ puts ""
368
+ puts "E.g. what we'd do to start Stripe off (if we didn't already do it):"
369
+ puts " bin/super-scaffold oauth-provider omniauth-stripe-connect stripe_connect Oauth::StripeAccount STRIPE_CLIENT_ID STRIPE_SECRET_KEY --icon=ti-money"
370
+ puts ""
371
+ puts "E.g. what we actually did to start Shopify off:"
372
+ puts " bin/super-scaffold oauth-provider omniauth-shopify-oauth2 shopify Oauth::ShopifyAccount SHOPIFY_API_KEY SHOPIFY_API_SECRET_KEY --icon=ti-shopping-cart"
373
+ puts ""
374
+ puts "Options:"
375
+ puts ""
376
+ puts " --icon={ti-*}: Specify an icon."
377
+ puts ""
378
+ puts "For a list of readily available provider strategies, see https://github.com/omniauth/omniauth/wiki/List-of-Strategies ."
379
+ puts ""
380
+ exit
381
+ end
382
+
383
+ _, omniauth_gem, gems_provider_name, our_provider_name, api_key, api_secret = *ARGV
384
+
385
+ unless match = our_provider_name.match(/Oauth::(.*)Account/)
386
+ puts "\n🚨 Your provider name must match the pattern of `Oauth::{Name}Account`, e.g. `Oauth::StripeAccount`\n".red
387
+ return
388
+ end
389
+
390
+ options = {
391
+ omniauth_gem: omniauth_gem,
392
+ gems_provider_name: gems_provider_name,
393
+ our_provider_name: match[1],
394
+ api_key: api_key,
395
+ api_secret: api_secret
396
+ }
397
+
398
+ unless File.exist?(oauth_transform_string("./app/models/oauth/stripe_account.rb", options)) &&
399
+ File.exist?(oauth_transform_string("./app/models/integrations/stripe_installation.rb", options)) &&
400
+ File.exist?(oauth_transform_string("./app/models/webhooks/incoming/oauth/stripe_account_webhook.rb", options))
401
+ puts ""
402
+ puts oauth_transform_string("🚨 Before doing the actual Super Scaffolding, you'll need to generate the models like so:", options).red
403
+ puts ""
404
+ puts oauth_transform_string(" rails g model Oauth::StripeAccount uid:string data:jsonb user:references", options).red
405
+ puts oauth_transform_string(" rails g model Integrations::StripeInstallation team:references oauth_stripe_account:references name:string", options).red
406
+ 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
407
+ puts ""
408
+ 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
409
+ puts ""
410
+ return
411
+ end
412
+
413
+ icon_name = nil
414
+ if @options["icon"].present?
415
+ icon_name = @options["icon"]
416
+ else
417
+ puts "OK, great! Let's do this! By default providers will appear with a dollar symbol,"
418
+ puts "but after you hit enter I'll open a page where you can view other icon options."
419
+ puts "When you find one you like, hover your mouse over it and then come back here and"
420
+ puts "and enter the name of the icon you want to use."
421
+ response = STDIN.gets.chomp
422
+ `open http://light.pinsupreme.com/icon_fonts_themefy.html`
423
+ puts ""
424
+ puts "Did you find an icon you wanted to use? Enter the name here or hit enter to just"
425
+ puts "use the dollar symbol:"
426
+ icon_name = STDIN.gets.chomp
427
+ puts ""
428
+ unless icon_name.length > 0 || icon_name.downcase == "y"
429
+ icon_name = "icon-puzzle"
430
+ end
431
+ end
432
+
433
+ options[:icon] = icon_name
434
+
435
+ [
436
+
437
+ # User OAuth.
438
+ "./app/models/oauth/stripe_account.rb",
439
+ "./app/models/webhooks/incoming/oauth/stripe_account_webhook.rb",
440
+ "./app/controllers/account/oauth/stripe_accounts_controller.rb",
441
+ "./app/controllers/webhooks/incoming/oauth/stripe_account_webhooks_controller.rb",
442
+ "./app/views/account/oauth/stripe_accounts",
443
+ "./test/models/oauth/stripe_account_test.rb",
444
+ "./test/factories/oauth/stripe_accounts.rb",
445
+ "./config/locales/en/oauth/stripe_accounts.en.yml",
446
+ "./app/views/devise/shared/oauth/_stripe.html.erb",
447
+
448
+ # Team Integration.
449
+ "./app/models/integrations/stripe_installation.rb",
450
+ # './app/serializers/api/v1/integrations/stripe_installation_serializer.rb',
451
+ "./app/controllers/account/integrations/stripe_installations_controller.rb",
452
+ "./app/views/account/integrations/stripe_installations",
453
+ "./test/models/integrations/stripe_installation_test.rb",
454
+ "./test/factories/integrations/stripe_installations.rb",
455
+ "./config/locales/en/integrations/stripe_installations.en.yml",
456
+
457
+ # Webhook.
458
+ "./app/models/webhooks/incoming/oauth/stripe_account_webhook.rb",
459
+ "./app/controllers/webhooks/incoming/oauth/stripe_account_webhooks_controller.rb"
460
+
461
+ ].each do |name|
462
+ if File.directory?(name)
463
+ oauth_scaffold_directory(name, options)
464
+ else
465
+ oauth_scaffold_file(name, options)
466
+ end
467
+ end
468
+
469
+ 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)
470
+ 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)
471
+ 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)
472
+ 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)
473
+ 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)
474
+ 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)
475
+ 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)
476
+ 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)
477
+ 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)
478
+ 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)
479
+ 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)
480
+ oauth_scaffold_add_line_to_file("./Gemfile", "gem 'omniauth-stripe-connect'", "# 🚅 super scaffolding will insert new oauth providers above this line.", options, prepend: true)
481
+ 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)
482
+ 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)
483
+ oauth_scaffold_add_line_to_file("./app/models/ability.rb", "if stripe_enabled?
484
+ can [:read, :create, :destroy], Oauth::StripeAccount, user_id: user.id
485
+ can :manage, Integrations::StripeInstallation, team_id: user.team_ids
486
+ can :destroy, Integrations::StripeInstallation, oauth_stripe_account: {user_id: user.id}
487
+ end
488
+ ", "# 🚅 super scaffolding will insert any new oauth providers above.", options, prepend: true)
489
+
490
+ # find the database migration that defines this relationship.
491
+ migration_file_name = `grep "create_table #{oauth_transform_string(":oauth_stripe_accounts", options)}" db/migrate/*`.split(":").first
492
+ legacy_replace_in_file(migration_file_name, "null: false", "null: true")
493
+
494
+ migration_file_name = `grep "create_table #{oauth_transform_string(":integrations_stripe_installations", options)}" db/migrate/*`.split(":").first
495
+ legacy_replace_in_file(migration_file_name,
496
+ oauth_transform_string("t.references :oauth_stripe_account, null: false, foreign_key: true", options),
497
+ oauth_transform_string('t.references :oauth_stripe_account, null: false, foreign_key: true, index: {name: "index_stripe_installations_on_oauth_stripe_account_id"}', options))
498
+
499
+ migration_file_name = `grep "create_table #{oauth_transform_string(":webhooks_incoming_oauth_stripe_account_webhooks", options)}" db/migrate/*`.split(":").first
500
+ legacy_replace_in_file(migration_file_name, "null: false", "null: true")
501
+ legacy_replace_in_file(migration_file_name, "foreign_key: true", 'foreign_key: true, index: {name: "index_stripe_webhooks_on_oauth_stripe_account_id"}')
502
+
503
+ puts ""
504
+ puts "🎉"
505
+ puts ""
506
+ puts "You'll probably need to `bundle install`.".green
507
+ puts ""
508
+ puts "If the OAuth provider asks you for some whitelisted callback URLs, the URL structure for those is as so:"
509
+ puts ""
510
+ path = "users/auth/stripe_connect/callback"
511
+ puts oauth_transform_string(" https://yourdomain.co/#{path}", options)
512
+ puts oauth_transform_string(" https://yourtunnel.ngrok.io/#{path}", options)
513
+ puts oauth_transform_string(" http://localhost:3000/#{path}", options)
514
+ puts ""
515
+ puts "If you're able to specify an endpoint to receive webhooks from this provider, use this URL:"
516
+ puts ""
517
+ path = "webhooks/incoming/oauth/stripe_account_webhooks"
518
+ puts oauth_transform_string(" https://yourdomain.co/#{path}", options)
519
+ puts oauth_transform_string(" https://yourtunnel.ngrok.io/#{path}", options)
520
+ puts oauth_transform_string(" http://localhost:3000/#{path}", options)
521
+ puts ""
522
+ puts ""
523
+ 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`."
524
+ puts ""
525
+ 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`."
526
+ puts ""
527
+
528
+ elsif argv.count > 1
529
+
530
+ puts ""
531
+ puts "👋"
532
+ puts "The command line options for Super Scaffolding have changed slightly:".yellow
533
+ puts "To use the original Super Scaffolding that you know and love, use the `crud` option.".yellow
534
+ show_usage
535
+
536
+ else
537
+ if ARGV.first.present?
538
+ puts ""
539
+ puts "Invalid scaffolding type \"#{ARGV.first}\".".red
540
+ end
541
+
542
+ show_usage
543
+ end