bullet_train-super_scaffolding 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +28 -0
- data/Rakefile +8 -0
- data/app/assets/config/bullet_train_super_scaffolding_manifest.js +0 -0
- data/config/routes.rb +2 -0
- data/lib/bullet_train/super_scaffolding/engine.rb +6 -0
- data/lib/bullet_train/super_scaffolding/version.rb +5 -0
- data/lib/bullet_train/super_scaffolding.rb +8 -0
- data/lib/scaffolding/class_names_transformer.rb +190 -0
- data/lib/scaffolding/oauth_providers.rb +107 -0
- data/lib/scaffolding/routes_file_manipulator.rb +384 -0
- data/lib/scaffolding/script.rb +543 -0
- data/lib/scaffolding/transformer.rb +1365 -0
- data/lib/scaffolding.rb +8 -0
- data/lib/tasks/bullet_train/super_scaffolding_tasks.rake +4 -0
- metadata +74 -0
@@ -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
|