brick 1.0.111 → 1.0.113
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 +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
|