bullet_train-super_scaffolding 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|