brick 1.0.111 → 1.0.113
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/brick/extensions.rb +21 -6
- data/lib/brick/frameworks/rails/engine.rb +76 -24
- data/lib/brick/frameworks/rails/form_tags.rb +3 -2
- data/lib/brick/version_number.rb +1 -1
- data/lib/brick.rb +233 -233
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f6cede45ed1fd983a2199fb279dffad0ecd02e51c7ed31cec6d46fccbc799e7c
|
4
|
+
data.tar.gz: 65eb5df73a7869b1bbe3ac128a69b4fda257e9dc098e77dc65c75d8f593756d7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0e506c2b4d00a1402e232f48c9eb95fc1edfb201a4b2d46ce8fd2a29d0f6a62e5d954ba84dfad4ccab2ff2c5c972d32478873e1f5c7ddf19bdfcca24894b0d1e
|
7
|
+
data.tar.gz: ee7dd85c423043b10efb60075716e3464db2645ac642fa43f457cf1b05c98a52cb7645e58e3a8208be8fd94b3a4b74f6b7d5e3102d890d087542a04b7e8cc7ec
|
data/lib/brick/extensions.rb
CHANGED
@@ -1602,11 +1602,11 @@ class Object
|
|
1602
1602
|
else
|
1603
1603
|
relation.last[:cols]
|
1604
1604
|
end
|
1605
|
-
{ :index => [:get, 'list'], :create => [:post, 'create a'] }.each do |k, v|
|
1605
|
+
{ :index => [:get, 'list', true], :create => [:post, 'create a', false] }.each do |k, v|
|
1606
1606
|
unless actions&.exclude?(k)
|
1607
1607
|
this_resource = (s["#{current_api_root}#{relation_name}"] ||= {})
|
1608
1608
|
this_resource[v.first] = {
|
1609
|
-
'summary': "#{v[1]} #{relation.first}",
|
1609
|
+
'summary': "#{v[1]} #{relation.first.send(v[2] ? :pluralize : :singularize)}",
|
1610
1610
|
'description': table_description,
|
1611
1611
|
'parameters': renamed_columns.map do |k2, v2|
|
1612
1612
|
param = { in: 'query', 'name': k2, 'schema': { 'type': v2.first } }
|
@@ -1841,7 +1841,19 @@ class Object
|
|
1841
1841
|
end
|
1842
1842
|
|
1843
1843
|
instance_variable_set("@#{singular_table_name}".to_sym, (obj = find_obj))
|
1844
|
-
|
1844
|
+
upd_params = send(params_name_sym)
|
1845
|
+
if (json_cols = model.columns.select { |c| c.type == :json }.map(&:name)).present?
|
1846
|
+
upd_hash = upd_params.to_h
|
1847
|
+
json_cols.each do |c|
|
1848
|
+
begin
|
1849
|
+
upd_hash[c] = JSON.parse(upd_hash[c]) # At least attempt to turn this into a parsed hash or array object
|
1850
|
+
rescue
|
1851
|
+
end
|
1852
|
+
end
|
1853
|
+
obj.send(:update, upd_hash)
|
1854
|
+
else
|
1855
|
+
obj.send(:update, upd_params)
|
1856
|
+
end
|
1845
1857
|
end
|
1846
1858
|
|
1847
1859
|
code << " def destroy\n"
|
@@ -1865,11 +1877,14 @@ class Object
|
|
1865
1877
|
@#{singular_table_name} = #{model.name}.find(id.is_a?(Array) && id.length == 1 ? id.first : id)
|
1866
1878
|
end\n"
|
1867
1879
|
self.define_method :find_obj do
|
1868
|
-
id = if model.columns_hash[pk.first]&.type == :string
|
1869
|
-
is_pk_string = true
|
1880
|
+
id = if pk.length == 1 # && model.columns_hash[pk.first]&.type == :string
|
1870
1881
|
params[:id].gsub('^^sl^^', '/')
|
1871
1882
|
else
|
1872
|
-
|
1883
|
+
if model.columns_hash[pk.first]&.type == :string
|
1884
|
+
params[:id]&.split('/')
|
1885
|
+
else
|
1886
|
+
params[:id]&.split(/[\/,_]/)
|
1887
|
+
end.map do |val_part|
|
1873
1888
|
val_part.gsub('^^sl^^', '/')
|
1874
1889
|
end
|
1875
1890
|
end
|
@@ -322,18 +322,26 @@ window.addEventListener(\"popstate\", linkSchemas);
|
|
322
322
|
end
|
323
323
|
|
324
324
|
def set_brick_model(find_args)
|
325
|
-
#
|
326
|
-
#
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
325
|
+
# Return an appropriate model for a given view template request.
|
326
|
+
# find_args will generally be something like: ["index", ["categories"]]
|
327
|
+
# and must cycle through all of find_args[1] because in some cases such as with Devise we get something like:
|
328
|
+
# ["create", ["users/sessions", "sessions", "devise/sessions", "devise", "application"], false, []]
|
329
|
+
find_args[1]&.any? do |resource_name|
|
330
|
+
if (class_name = (resource_parts = resource_name.split('/')).last&.singularize)
|
331
|
+
resource_parts[-1] = class_name # Make sure the last part, defining the class name, is singular
|
332
|
+
begin
|
333
|
+
if (model = Object.const_get(resource_parts.map(&:camelize).join('::')))&.is_a?(Class) && (
|
334
|
+
['index', 'show'].include?(find_args.first) || # Everything has index and show
|
335
|
+
# Only CUD stuff has create / update / destroy
|
336
|
+
(!model.is_view? && ['new', 'create', 'edit', 'update', 'destroy'].include?(find_args.first))
|
337
|
+
)
|
338
|
+
@_brick_model = model
|
339
|
+
end
|
340
|
+
rescue
|
341
|
+
end
|
335
342
|
end
|
336
343
|
end
|
344
|
+
@_brick_model
|
337
345
|
end
|
338
346
|
|
339
347
|
def path_keys(hm_assoc, fk_name, pk)
|
@@ -356,6 +364,7 @@ window.addEventListener(\"popstate\", linkSchemas);
|
|
356
364
|
|
357
365
|
alias :_brick_find_template :find_template
|
358
366
|
def find_template(*args, **options)
|
367
|
+
find_template_err = nil
|
359
368
|
unless (model_name = @_brick_model&.name) ||
|
360
369
|
(is_status = ::Brick.config.add_status && args[0..1] == ['status', ['brick_gem']]) ||
|
361
370
|
(is_orphans = ::Brick.config.add_orphans && args[0..1] == ['orphans', ['brick_gem']]) ||
|
@@ -364,10 +373,11 @@ window.addEventListener(\"popstate\", linkSchemas);
|
|
364
373
|
if (possible_template = _brick_find_template(*args, **options))
|
365
374
|
return possible_template
|
366
375
|
end
|
367
|
-
rescue
|
376
|
+
rescue StandardError => e
|
377
|
+
find_template_err = e # Can come up with stuff like Devise which has its own view templates
|
368
378
|
end
|
369
379
|
# Used to also have: ActionView.version < ::Gem::Version.new('5.0') &&
|
370
|
-
model_name =
|
380
|
+
model_name = set_brick_model(args)&.name
|
371
381
|
end
|
372
382
|
|
373
383
|
if @_brick_model
|
@@ -638,15 +648,19 @@ input+svg.revert {
|
|
638
648
|
</style>
|
639
649
|
|
640
650
|
<% is_includes_dates = nil
|
651
|
+
is_includes_json = nil
|
641
652
|
def is_bcrypt?(val)
|
642
653
|
val.is_a?(String) && val.length == 60 && val.start_with?('$2a$')
|
643
654
|
end
|
644
|
-
def hide_bcrypt(val, max_len = 200)
|
655
|
+
def hide_bcrypt(val, is_xml = nil, max_len = 200)
|
645
656
|
if is_bcrypt?(val)
|
646
657
|
'(hidden)'
|
647
658
|
else
|
648
659
|
if val.is_a?(String)
|
649
|
-
|
660
|
+
val = val.dup.force_encoding('UTF-8').strip
|
661
|
+
return CGI.escapeHTML(val) if is_xml
|
662
|
+
|
663
|
+
if val.length > max_len
|
650
664
|
if val[0] == '<' # Seems to be HTML?
|
651
665
|
cur_len = 0
|
652
666
|
cur_idx = 0
|
@@ -693,7 +707,6 @@ def hide_bcrypt(val, max_len = 200)
|
|
693
707
|
end
|
694
708
|
val = \"#\{val}...\"
|
695
709
|
end
|
696
|
-
val = val.dup.force_encoding('UTF-8') unless val.encoding.name == 'UTF-8'
|
697
710
|
val
|
698
711
|
else
|
699
712
|
val.to_s
|
@@ -758,7 +771,7 @@ def display_value(col_type, val)
|
|
758
771
|
display_binary(val) if val
|
759
772
|
else
|
760
773
|
if col_type
|
761
|
-
hide_bcrypt(val)
|
774
|
+
hide_bcrypt(val, col_type == :xml)
|
762
775
|
else
|
763
776
|
'?'
|
764
777
|
end
|
@@ -1154,7 +1167,7 @@ erDiagram
|
|
1154
1167
|
td_count += 1 %>
|
1155
1168
|
<td><%= link_to_brick(
|
1156
1169
|
avo_svg,
|
1157
|
-
{ index_proc: Proc.new do |
|
1170
|
+
{ index_proc: Proc.new do |_avo_model, relation|
|
1158
1171
|
path_helper = \"resources_#\{relation.fetch(:auto_prefixed_schema, nil)}#\{model.model_name.route_key}_path\".to_sym
|
1159
1172
|
::Avo.railtie_routes_url_helpers.send(path_helper) if ::Avo.railtie_routes_url_helpers.respond_to?(path_helper)
|
1160
1173
|
end,
|
@@ -1429,18 +1442,16 @@ end
|
|
1429
1442
|
when :string, :text %>
|
1430
1443
|
<% if is_bcrypt?(val) # || .readonly?
|
1431
1444
|
is_revert = false %>
|
1432
|
-
<%= hide_bcrypt(val, 1000) %>
|
1445
|
+
<%= hide_bcrypt(val, nil, 1000) %>
|
1433
1446
|
<% else %>
|
1434
1447
|
<%= f.text_field(k.to_sym, html_options) %>
|
1435
1448
|
<% end %>
|
1436
1449
|
<% when :boolean %>
|
1437
1450
|
<%= f.check_box k.to_sym %>
|
1438
1451
|
<% when :integer, :decimal, :float %>
|
1439
|
-
<%=
|
1440
|
-
|
1441
|
-
|
1442
|
-
f.number_field k.to_sym
|
1443
|
-
end %>
|
1452
|
+
<%= digit_pattern = col_type == :integer ? '\\d*' : '\\d*(?:\\.\\d*|)'
|
1453
|
+
# Used to do this for float / decimal: f.number_field k.to_sym
|
1454
|
+
f.text_field k.to_sym, { pattern: digit_pattern, class: 'check-validity' } %>
|
1444
1455
|
<% when *dt_pickers.keys
|
1445
1456
|
is_includes_dates = true %>
|
1446
1457
|
<%= f.text_field k.to_sym, { class: dt_pickers[col_type] } %>
|
@@ -1468,6 +1479,13 @@ end
|
|
1468
1479
|
end %>
|
1469
1480
|
<% when :primary_key
|
1470
1481
|
is_revert = false %>
|
1482
|
+
<% when :json
|
1483
|
+
is_includes_json = true %>
|
1484
|
+
<%= # Because there are so danged many quotes in JSON, escape them specially by converting to backticks.
|
1485
|
+
# (and previous to this, escape backticks with our own goofy code of ^^br_btick__ )
|
1486
|
+
val_str = val.is_a?(String) ? val : val.to_json # Clean up bogus JSON if necessary
|
1487
|
+
json_field = f.hidden_field k.to_sym, { class: 'jsonpicker', value: val_str.gsub('`', '^^br_btick__').tr('\"', '`').html_safe } %>
|
1488
|
+
<div id=\"_br_json_<%= f.field_id(k) %>\"></div>
|
1471
1489
|
<% else %>
|
1472
1490
|
<%= is_revert = false
|
1473
1491
|
display_value(col_type, val).html_safe %>
|
@@ -1542,7 +1560,12 @@ end}
|
|
1542
1560
|
</body>
|
1543
1561
|
</html>
|
1544
1562
|
"
|
1545
|
-
|
1563
|
+
else # args.first isn't index / show / edit / new / orphans / status
|
1564
|
+
if find_template_err # Can surface when gems have their own view templates
|
1565
|
+
raise find_template_err
|
1566
|
+
else # Can surface if someone made their own controller which has a screwy action
|
1567
|
+
puts "Couldn't work with action #{args.first}"
|
1568
|
+
end
|
1546
1569
|
end
|
1547
1570
|
unless is_crosstab
|
1548
1571
|
inline << "
|
@@ -1566,6 +1589,35 @@ flatpickr(\".timepicker\", {enableTime: true, noCalendar: true});
|
|
1566
1589
|
<link rel=\"stylesheet\" type=\"text/css\" href=\"https://cdnjs.cloudflare.com/ajax/libs/slim-select/1.27.1/slimselect.min.css\">
|
1567
1590
|
<% end %>
|
1568
1591
|
|
1592
|
+
<% # Started with v0.14.4 of vanilla-jsoneditor
|
1593
|
+
if is_includes_json %>
|
1594
|
+
<link rel=\"stylesheet\" type=\"text/css\" href=\"https://cdn.jsdelivr.net/npm/vanilla-jsoneditor/themes/jse-theme-default.min.css\">
|
1595
|
+
<script type=\"module\">
|
1596
|
+
import { JSONEditor } from \"https://cdn.jsdelivr.net/npm/vanilla-jsoneditor/index.min.js\";
|
1597
|
+
document.querySelectorAll(\"input.jsonpicker\").forEach(function (inp) {
|
1598
|
+
var jsonDiv;
|
1599
|
+
if (jsonDiv = document.getElementById(\"_br_json_\" + inp.id)) {
|
1600
|
+
new JSONEditor({
|
1601
|
+
target: jsonDiv,
|
1602
|
+
props: {
|
1603
|
+
// Instead of text can also do: { json: JSONValue }
|
1604
|
+
// Other options: name: \"taco\", mode: \"tree\", navigationBar: false, mainMenuBar: false, statusBar: false, search: false, templates:, history: false
|
1605
|
+
content: {text: inp.value.replace(/`/g, '\"').replace(/\\^\\^br_btick__/g, \"`\")},
|
1606
|
+
onChange: (function (inp2) {
|
1607
|
+
return function (updatedContent, previousContent, contentErrors, patchResult) {
|
1608
|
+
// console.log('onChange', updatedContent.json, updatedContent.text);
|
1609
|
+
inp2.value = updatedContent.text || JSON.stringify(updatedContent.json);
|
1610
|
+
};
|
1611
|
+
})(inp)
|
1612
|
+
}
|
1613
|
+
});
|
1614
|
+
} else {
|
1615
|
+
console.log(\"Could not find JSON picker for \" + inp.id);
|
1616
|
+
}
|
1617
|
+
});
|
1618
|
+
</script>
|
1619
|
+
<% end %>
|
1620
|
+
|
1569
1621
|
<% if true # @_brick_erd
|
1570
1622
|
%>
|
1571
1623
|
<script>
|
@@ -116,7 +116,7 @@ module Brick::Rails::FormTags
|
|
116
116
|
end
|
117
117
|
end
|
118
118
|
elsif (col = cols[col_name]).is_a?(ActiveRecord::ConnectionAdapters::Column)
|
119
|
-
binding.pry if col.is_a?(Array)
|
119
|
+
# binding.pry if col.is_a?(Array)
|
120
120
|
col_type = col&.sql_type == 'geography' ? col.sql_type : col&.type
|
121
121
|
out << display_value(col_type || col&.sql_type, val).to_s
|
122
122
|
elsif cust_col
|
@@ -201,7 +201,8 @@ module Brick::Rails::FormTags
|
|
201
201
|
end
|
202
202
|
filter = "?#{filter_parts.join('&')}" if filter_parts.present?
|
203
203
|
app_routes = Rails.application.routes # In case we're operating in another engine, reference the application since Brick routes are placed there.
|
204
|
-
|
204
|
+
klass = klass_or_obj.is_a?(ActiveRecord::Base) ? klass_or_obj.class : klass_or_obj
|
205
|
+
relation = ::Brick.relations.fetch(rel_name || klass.table_name, nil)
|
205
206
|
if (klass_or_obj&.is_a?(Class) && klass_or_obj < ActiveRecord::Base) ||
|
206
207
|
(klass_or_obj&.is_a?(ActiveRecord::Base) && klass_or_obj.new_record? && (klass_or_obj = klass_or_obj.class))
|
207
208
|
path = (proc = kwargs[:index_proc]) ? proc.call(klass_or_obj, relation) : "#{app_routes.path_for(controller: klass_or_obj.base_class._brick_index(nil, '/', relation), action: :index)}#{filter}"
|
data/lib/brick/version_number.rb
CHANGED
data/lib/brick.rb
CHANGED
@@ -654,270 +654,270 @@ In config/initializers/brick.rb appropriate entries would look something like:
|
|
654
654
|
|
655
655
|
module RouteSet
|
656
656
|
def finalize!
|
657
|
-
|
658
|
-
unless
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
657
|
+
routeset_to_use = ::Rails.application.routes
|
658
|
+
return super unless self == routeset_to_use
|
659
|
+
|
660
|
+
path_prefix = ::Brick.config.path_prefix
|
661
|
+
existing_controllers = routes.each_with_object({}) do |r, s|
|
662
|
+
c = r.defaults[:controller]
|
663
|
+
s[c] = nil if c
|
664
|
+
end
|
665
|
+
append do
|
666
|
+
tables = []
|
667
|
+
views = []
|
668
|
+
table_class_length = 38 # Length of "Classes that can be built from tables:"
|
669
|
+
view_class_length = 37 # Length of "Classes that can be built from views:"
|
670
|
+
|
671
|
+
brick_namespace_create = lambda do |path_names, res_name, options|
|
672
|
+
if path_names&.present?
|
673
|
+
if (path_name = path_names.pop).is_a?(Array)
|
674
|
+
module_name = path_name[1]
|
675
|
+
path_name = path_name.first
|
676
|
+
end
|
677
|
+
send(:scope, { module: module_name || path_name, path: path_name, as: path_name }) do
|
678
|
+
brick_namespace_create.call(path_names, res_name, options)
|
679
|
+
end
|
680
|
+
else
|
681
|
+
send(:resources, res_name.to_sym, **options)
|
682
|
+
end
|
663
683
|
end
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
684
|
+
|
685
|
+
# %%% TODO: If no auto-controllers then enumerate the controllers folder in order to build matching routes
|
686
|
+
# If auto-controllers and auto-models are both enabled then this makes sense:
|
687
|
+
controller_prefix = (path_prefix ? "#{path_prefix}/" : '')
|
688
|
+
sti_subclasses = ::Brick.config.sti_namespace_prefixes.each_with_object(Hash.new { |h, k| h[k] = [] }) do |v, s|
|
689
|
+
# Turn something like {"::Spouse"=>"Person", "::Friend"=>"Person"} into {"Person"=>["Spouse", "Friend"]}
|
690
|
+
s[v.last] << v.first[2..-1] unless v.first.end_with?('::')
|
691
|
+
end
|
692
|
+
versioned_views = {} # Track which views have already been done for each api_root
|
693
|
+
::Brick.relations.each do |k, v|
|
694
|
+
if (schema_name = v.fetch(:schema, nil))
|
695
|
+
schema_prefix = "#{schema_name}."
|
696
|
+
end
|
697
|
+
|
698
|
+
next if !(resource_name = v.fetch(:resource, nil)) ||
|
699
|
+
existing_controllers.key?(
|
700
|
+
controller_prefix + (resource_name = "#{schema_prefix&.tr('.', '/')}#{resource_name}".pluralize)
|
701
|
+
)
|
702
|
+
|
703
|
+
object_name = k.split('.').last # Take off any first schema part
|
704
|
+
|
705
|
+
full_schema_prefix = if (aps = v.fetch(:auto_prefixed_schema, nil))
|
706
|
+
aps = aps[0..-2] if aps[-1] == '_'
|
707
|
+
(schema_prefix&.dup || +'') << "#{aps}."
|
708
|
+
else
|
709
|
+
schema_prefix
|
710
|
+
end
|
711
|
+
|
712
|
+
# Track routes being built
|
713
|
+
if (class_name = v.fetch(:class_name, nil))
|
714
|
+
if v.key?(:isView)
|
715
|
+
view_class_length = class_name.length if class_name.length > view_class_length
|
716
|
+
views
|
679
717
|
else
|
680
|
-
|
681
|
-
|
718
|
+
table_class_length = class_name.length if class_name.length > table_class_length
|
719
|
+
tables
|
720
|
+
end << [class_name, aps, resource_name]
|
682
721
|
end
|
683
722
|
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
723
|
+
options = {}
|
724
|
+
options[:only] = [:index, :show] if v.key?(:isView)
|
725
|
+
|
726
|
+
# First do the normal routes
|
727
|
+
prefixes = []
|
728
|
+
prefixes << [aps, v[:class_name]&.split('::')[-2]&.underscore] if aps
|
729
|
+
prefixes << schema_name if schema_name
|
730
|
+
prefixes << path_prefix if path_prefix
|
731
|
+
brick_namespace_create.call(prefixes, v[:resource], options)
|
732
|
+
sti_subclasses.fetch(class_name, nil)&.each do |sc| # Add any STI subclass routes for this relation
|
733
|
+
brick_namespace_create.call(prefixes, sc.underscore.tr('/', '_').pluralize, options)
|
734
|
+
end
|
696
735
|
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
736
|
+
# Now the API routes if necessary
|
737
|
+
full_resource = nil
|
738
|
+
::Brick.api_roots&.each do |api_root|
|
739
|
+
api_done_views = (versioned_views[api_root] ||= {})
|
740
|
+
found = nil
|
741
|
+
test_ver_num = nil
|
742
|
+
view_relation = nil
|
743
|
+
# If it's a view then see if there's a versioned one available by searching for resource names
|
744
|
+
# versioned with the closest number (equal to or less than) compared with our API version number.
|
745
|
+
if v.key?(:isView)
|
746
|
+
if (ver = object_name.match(/^v([\d_]*)/)&.captures&.first) && ver[-1] == '_'
|
747
|
+
core_object_name = object_name[ver.length + 1..-1]
|
748
|
+
next if api_done_views.key?(unversioned = "#{schema_prefix}v_#{core_object_name}")
|
749
|
+
|
750
|
+
# Expect that the last item in the path generally holds versioning information
|
751
|
+
api_ver = api_root.split('/')[-1]&.gsub('_', '.')
|
752
|
+
vn_idx = api_ver.rindex(/[^\d._]/) # Position of the first numeric digit at the end of the version number
|
753
|
+
# Was: .to_d
|
754
|
+
test_ver_num = api_ver_num = api_ver[vn_idx + 1..-1].gsub('_', '.').to_i # Attempt to turn something like "v3" into the decimal value 3
|
755
|
+
# puts [api_ver, vn_idx, api_ver_num, unversioned].inspect
|
756
|
+
|
757
|
+
next if ver.to_i > api_ver_num # Don't surface any newer views in an older API
|
758
|
+
|
759
|
+
test_ver_num -= 1 until test_ver_num.zero? ||
|
760
|
+
(view_relation = ::Brick.relations.fetch(
|
761
|
+
found = "#{schema_prefix}v#{test_ver_num}_#{core_object_name}", nil
|
762
|
+
))
|
763
|
+
api_done_views[unversioned] = nil # Mark that for this API version this view is done
|
764
|
+
|
765
|
+
# puts "Found #{found}" if view_relation
|
766
|
+
# If we haven't found "v3_view_name" or "v2_view_name" or so forth, at the last
|
767
|
+
# fall back to simply looking for "v_view_name", and then finally "view_name".
|
768
|
+
no_v_prefix_name = "#{schema_prefix}#{core_object_name}"
|
769
|
+
standard_prefix = 'v_'
|
716
770
|
else
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
prefixes = []
|
727
|
-
prefixes << [aps, v[:class_name]&.split('::')[-2]&.underscore] if aps
|
728
|
-
prefixes << schema_name if schema_name
|
729
|
-
prefixes << path_prefix if path_prefix
|
730
|
-
brick_namespace_create.call(prefixes, v[:resource], options)
|
731
|
-
sti_subclasses.fetch(class_name, nil)&.each do |sc| # Add any STI subclass routes for this relation
|
732
|
-
brick_namespace_create.call(prefixes, sc.underscore.tr('/', '_').pluralize, options)
|
771
|
+
core_object_name = object_name
|
772
|
+
end
|
773
|
+
if (rvp = ::Brick.config.api_remove_view_prefix) && core_object_name.start_with?(rvp)
|
774
|
+
core_object_name.slice!(0, rvp.length)
|
775
|
+
end
|
776
|
+
no_prefix_name = "#{schema_prefix}#{core_object_name}"
|
777
|
+
unversioned = "#{schema_prefix}#{standard_prefix}#{::Brick.config.api_add_view_prefix}#{core_object_name}"
|
778
|
+
else
|
779
|
+
unversioned = k
|
733
780
|
end
|
734
781
|
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
#
|
743
|
-
#
|
744
|
-
if
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
# puts "Found #{found}" if view_relation
|
765
|
-
# If we haven't found "v3_view_name" or "v2_view_name" or so forth, at the last
|
766
|
-
# fall back to simply looking for "v_view_name", and then finally "view_name".
|
767
|
-
no_v_prefix_name = "#{schema_prefix}#{core_object_name}"
|
768
|
-
standard_prefix = 'v_'
|
769
|
-
else
|
770
|
-
core_object_name = object_name
|
771
|
-
end
|
772
|
-
if (rvp = ::Brick.config.api_remove_view_prefix) && core_object_name.start_with?(rvp)
|
773
|
-
core_object_name.slice!(0, rvp.length)
|
782
|
+
view_relation ||= ::Brick.relations.fetch(found = unversioned, nil) ||
|
783
|
+
(no_v_prefix_name && ::Brick.relations.fetch(found = no_v_prefix_name, nil)) ||
|
784
|
+
(no_prefix_name && ::Brick.relations.fetch(found = no_prefix_name, nil))
|
785
|
+
if view_relation
|
786
|
+
actions = view_relation.key?(:isView) ? [:index, :show] : ::Brick::ALL_API_ACTIONS # By default all actions are allowed
|
787
|
+
# Call proc that limits which endpoints get surfaced based on version, table or view name, method (get list / get one / post / patch / delete)
|
788
|
+
# Returning nil makes it do nothing, false makes it skip creating this endpoint, and an array of up to
|
789
|
+
# these 3 things controls and changes the nature of the endpoint that gets built:
|
790
|
+
# (updated api_name, name of different relation to route to, allowed actions such as :index, :show, :create, etc)
|
791
|
+
proc_result = if (filter = ::Brick.config.api_filter).is_a?(Proc)
|
792
|
+
begin
|
793
|
+
num_args = filter.arity.negative? ? 6 : filter.arity
|
794
|
+
filter.call(*[unversioned, k, view_relation, actions, api_ver_num, found, test_ver_num][0...num_args])
|
795
|
+
rescue StandardError => e
|
796
|
+
puts "::Brick.api_filter Proc error: #{e.message}"
|
797
|
+
end
|
798
|
+
end
|
799
|
+
# proc_result expects to receive back: [updated_api_name, to_other_relation, allowed_actions]
|
800
|
+
|
801
|
+
case proc_result
|
802
|
+
when NilClass
|
803
|
+
# Do nothing differently than what normal behaviour would be
|
804
|
+
when FalseClass # Skip implementing this endpoint
|
805
|
+
view_relation[:api][api_ver_num] = nil
|
806
|
+
next
|
807
|
+
when Array # Did they give back an array of actions?
|
808
|
+
unless proc_result.any? { |pr| ::Brick::ALL_API_ACTIONS.exclude?(pr) }
|
809
|
+
proc_result = [unversioned, to_relation, proc_result]
|
774
810
|
end
|
775
|
-
|
776
|
-
|
811
|
+
# Otherwise don't change this array because it's probably legit
|
812
|
+
when String
|
813
|
+
proc_result = [proc_result] # Treat this as the surfaced api_name (path) they want to use for this endpoint
|
777
814
|
else
|
778
|
-
|
815
|
+
puts "::Brick.api_filter Proc warning: Unable to parse this result returned: \n #{proc_result.inspect}"
|
816
|
+
proc_result = nil # Couldn't understand what in the world was returned
|
779
817
|
end
|
780
818
|
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
# these 3 things controls and changes the nature of the endpoint that gets built:
|
789
|
-
# (updated api_name, name of different relation to route to, allowed actions such as :index, :show, :create, etc)
|
790
|
-
proc_result = if (filter = ::Brick.config.api_filter).is_a?(Proc)
|
791
|
-
begin
|
792
|
-
num_args = filter.arity.negative? ? 6 : filter.arity
|
793
|
-
filter.call(*[unversioned, k, view_relation, actions, api_ver_num, found, test_ver_num][0...num_args])
|
794
|
-
rescue StandardError => e
|
795
|
-
puts "::Brick.api_filter Proc error: #{e.message}"
|
796
|
-
end
|
797
|
-
end
|
798
|
-
# proc_result expects to receive back: [updated_api_name, to_other_relation, allowed_actions]
|
799
|
-
|
800
|
-
case proc_result
|
801
|
-
when NilClass
|
802
|
-
# Do nothing differently than what normal behaviour would be
|
803
|
-
when FalseClass # Skip implementing this endpoint
|
804
|
-
view_relation[:api][api_ver_num] = nil
|
805
|
-
next
|
806
|
-
when Array # Did they give back an array of actions?
|
807
|
-
unless proc_result.any? { |pr| ::Brick::ALL_API_ACTIONS.exclude?(pr) }
|
808
|
-
proc_result = [unversioned, to_relation, proc_result]
|
819
|
+
if proc_result&.present?
|
820
|
+
if proc_result[1] # to_other_relation
|
821
|
+
if (new_view_relation = ::Brick.relations.fetch(proc_result[1], nil))
|
822
|
+
k = proc_result[1] # Route this call over to this different relation
|
823
|
+
view_relation = new_view_relation
|
824
|
+
else
|
825
|
+
puts "::Brick.api_filter Proc warning: Unable to find new suggested relation with name #{proc_result[1]} -- sticking with #{k} instead."
|
809
826
|
end
|
810
|
-
# Otherwise don't change this array because it's probably legit
|
811
|
-
when String
|
812
|
-
proc_result = [proc_result] # Treat this as the surfaced api_name (path) they want to use for this endpoint
|
813
|
-
else
|
814
|
-
puts "::Brick.api_filter Proc warning: Unable to parse this result returned: \n #{proc_result.inspect}"
|
815
|
-
proc_result = nil # Couldn't understand what in the world was returned
|
816
827
|
end
|
817
|
-
|
818
|
-
|
819
|
-
if proc_result[1] # to_other_relation
|
820
|
-
if (new_view_relation = ::Brick.relations.fetch(proc_result[1], nil))
|
821
|
-
k = proc_result[1] # Route this call over to this different relation
|
822
|
-
view_relation = new_view_relation
|
823
|
-
else
|
824
|
-
puts "::Brick.api_filter Proc warning: Unable to find new suggested relation with name #{proc_result[1]} -- sticking with #{k} instead."
|
825
|
-
end
|
826
|
-
end
|
827
|
-
if proc_result.first&.!=(k) # updated_api_name -- a different name than this relation would normally have
|
828
|
-
found = proc_result.first
|
829
|
-
end
|
830
|
-
actions &= proc_result[2] if proc_result[2] # allowed_actions
|
828
|
+
if proc_result.first&.!=(k) # updated_api_name -- a different name than this relation would normally have
|
829
|
+
found = proc_result.first
|
831
830
|
end
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
831
|
+
actions &= proc_result[2] if proc_result[2] # allowed_actions
|
832
|
+
end
|
833
|
+
(view_relation[:api][api_ver_num] ||= {})[unversioned] = actions # Add to the list of API paths this resource responds to
|
834
|
+
|
835
|
+
# view_ver_num = if (first_part = k.split('_').first) =~ /^v[\d_]+/
|
836
|
+
# first_part[1..-1].gsub('_', '.').to_i
|
837
|
+
# end
|
838
|
+
controller_name = if (last = view_relation.fetch(:resource, nil)&.pluralize)
|
839
|
+
"#{full_schema_prefix}#{last}"
|
840
|
+
else
|
841
|
+
found
|
842
|
+
end.tr('.', '/')
|
843
|
+
|
844
|
+
{ :index => 'get', :create => 'post' }.each do |action, method|
|
845
|
+
if actions.include?(action)
|
846
|
+
# Normally goes to something like: /api/v1/employees
|
847
|
+
send(method, "#{api_root}#{unversioned.tr('.', '/')}", { to: "#{controller_prefix}#{controller_name}##{action}" })
|
848
848
|
end
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
849
|
+
end
|
850
|
+
# %%% We do not yet surface the #show action
|
851
|
+
if (id_col = view_relation[:pk]&.first) # ID-dependent stuff
|
852
|
+
{ :update => ['put', 'patch'], :destroy => ['delete'] }.each do |action, methods|
|
853
|
+
if actions.include?(action)
|
854
|
+
methods.each do |method|
|
855
|
+
send(method, "#{api_root}#{unversioned.tr('.', '/')}/:#{id_col}", { to: "#{controller_prefix}#{controller_name}##{action}" })
|
856
856
|
end
|
857
857
|
end
|
858
858
|
end
|
859
859
|
end
|
860
860
|
end
|
861
861
|
end
|
862
|
+
end
|
862
863
|
|
863
|
-
|
864
|
-
|
865
|
-
|
864
|
+
if ::Brick.config.add_status && instance_variable_get(:@set).named_routes.names.exclude?(:brick_status)
|
865
|
+
get("/#{controller_prefix}brick_status", to: 'brick_gem#status', as: 'brick_status')
|
866
|
+
end
|
866
867
|
|
867
|
-
|
868
|
-
|
869
|
-
|
868
|
+
if ::Brick.config.add_orphans && instance_variable_get(:@set).named_routes.names.exclude?(:brick_orphans)
|
869
|
+
get("/#{controller_prefix}brick_orphans", to: 'brick_gem#orphans', as: 'brick_orphans')
|
870
|
+
end
|
870
871
|
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
|
872
|
+
if instance_variable_get(:@set).named_routes.names.exclude?(:brick_crosstab)
|
873
|
+
get("/#{controller_prefix}brick_crosstab", to: 'brick_gem#crosstab', as: 'brick_crosstab')
|
874
|
+
get("/#{controller_prefix}brick_crosstab/data", to: 'brick_gem#crosstab_data')
|
875
|
+
end
|
875
876
|
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
else
|
890
|
-
puts "In order to make documentation available you can put this into your routes.rb:"
|
891
|
-
puts " mount Rswag::Ui::Engine => '/#{first_endpoint_parts&.find(&:present?) || 'api-docs'}'"
|
892
|
-
end
|
877
|
+
unless ::Brick.routes_done
|
878
|
+
if Object.const_defined?('Rswag::Ui')
|
879
|
+
rswag_path = routeset_to_use.routes.find { |r| r.app.app == Rswag::Ui::Engine }&.instance_variable_get(:@path_formatter)&.instance_variable_get(:@parts)&.join
|
880
|
+
first_endpoint_parts = nil
|
881
|
+
(doc_endpoints = Rswag::Ui.config.config_object[:urls])&.each do |doc_endpoint|
|
882
|
+
puts "Mounting OpenApi 3.0 documentation endpoint for \"#{doc_endpoint[:name]}\" on #{doc_endpoint[:url]}"
|
883
|
+
send(:get, doc_endpoint[:url], { to: 'brick_openapi#index' })
|
884
|
+
endpoint_parts = doc_endpoint[:url]&.split('/')
|
885
|
+
first_endpoint_parts ||= endpoint_parts
|
886
|
+
end
|
887
|
+
if doc_endpoints.present?
|
888
|
+
if rswag_path && first_endpoint_parts
|
889
|
+
puts "API documentation now available when navigating to: /#{first_endpoint_parts&.find(&:present?)}/index.html"
|
893
890
|
else
|
894
|
-
|
891
|
+
puts "In order to make documentation available you can put this into your routes.rb:"
|
892
|
+
puts " mount Rswag::Ui::Engine => '/#{first_endpoint_parts&.find(&:present?) || 'api-docs'}'"
|
893
|
+
end
|
894
|
+
else
|
895
|
+
sample_path = rswag_path || '/api-docs'
|
896
|
+
puts
|
897
|
+
puts "Brick: rswag-ui gem detected -- to make OpenAPI 3.0 documentation available from a path such as '#{sample_path}/v1/swagger.json',"
|
898
|
+
puts ' put code such as this in an initializer:'
|
899
|
+
puts ' Rswag::Ui.configure do |config|'
|
900
|
+
puts " config.swagger_endpoint '#{sample_path}/v1/swagger.json', 'API V1 Docs'"
|
901
|
+
puts ' end'
|
902
|
+
unless rswag_path
|
895
903
|
puts
|
896
|
-
puts
|
897
|
-
puts
|
898
|
-
puts ' Rswag::Ui.configure do |config|'
|
899
|
-
puts " config.swagger_endpoint '#{sample_path}/v1/swagger.json', 'API V1 Docs'"
|
900
|
-
puts ' end'
|
901
|
-
unless rswag_path
|
902
|
-
puts
|
903
|
-
puts ' and put this into your routes.rb:'
|
904
|
-
puts " mount Rswag::Ui::Engine => '/api-docs'"
|
905
|
-
end
|
904
|
+
puts ' and put this into your routes.rb:'
|
905
|
+
puts " mount Rswag::Ui::Engine => '/api-docs'"
|
906
906
|
end
|
907
907
|
end
|
908
|
+
end
|
908
909
|
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
end
|
910
|
+
::Brick.routes_done = true
|
911
|
+
puts "\n" if tables.present? || views.present?
|
912
|
+
if tables.present?
|
913
|
+
puts "Classes that can be built from tables:#{' ' * (table_class_length - 38)} Path:"
|
914
|
+
puts "======================================#{' ' * (table_class_length - 38)} ====="
|
915
|
+
::Brick.display_classes(controller_prefix, tables, table_class_length)
|
916
|
+
end
|
917
|
+
if views.present?
|
918
|
+
puts "Classes that can be built from views:#{' ' * (view_class_length - 37)} Path:"
|
919
|
+
puts "=====================================#{' ' * (view_class_length - 37)} ====="
|
920
|
+
::Brick.display_classes(controller_prefix, views, view_class_length)
|
921
921
|
end
|
922
922
|
end
|
923
923
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: brick
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.113
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lorin Thwaits
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-02-
|
11
|
+
date: 2023-02-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|