brick 1.0.112 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 69051263cec00b3672b8d48b0c595ff6875b81f27e7995be72a03d6699ad6d02
4
- data.tar.gz: 217687ad2f6b93c33dc781f5930a0475a60fb27d782593109055beaae19f4e55
3
+ metadata.gz: f6cede45ed1fd983a2199fb279dffad0ecd02e51c7ed31cec6d46fccbc799e7c
4
+ data.tar.gz: 65eb5df73a7869b1bbe3ac128a69b4fda257e9dc098e77dc65c75d8f593756d7
5
5
  SHA512:
6
- metadata.gz: 6eff4c8a9f59673d14be1d890b067e17e631b1d6938a22b81c1ec45c3785489195d5d9e93939a38c681d36d844df2ad9a932584d8269b0fd2ef678de428c805c
7
- data.tar.gz: 723425258d449708f18e086f289147b3402f728c93fbcba3a16654c3d15b4fe715022e427cb3f87e731bf9b73d693a5d4f43a500bdbde3641b69ac61e4c35e35
6
+ metadata.gz: 0e506c2b4d00a1402e232f48c9eb95fc1edfb201a4b2d46ce8fd2a29d0f6a62e5d954ba84dfad4ccab2ff2c5c972d32478873e1f5c7ddf19bdfcca24894b0d1e
7
+ data.tar.gz: ee7dd85c423043b10efb60075716e3464db2645ac642fa43f457cf1b05c98a52cb7645e58e3a8208be8fd94b3a4b74f6b7d5e3102d890d087542a04b7e8cc7ec
@@ -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
- obj.send(:update, send(params_name_sym))
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
- params[:id]&.split(/[\/,_]/).map do |val_part|
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
@@ -648,15 +648,19 @@ input+svg.revert {
648
648
  </style>
649
649
 
650
650
  <% is_includes_dates = nil
651
+ is_includes_json = nil
651
652
  def is_bcrypt?(val)
652
653
  val.is_a?(String) && val.length == 60 && val.start_with?('$2a$')
653
654
  end
654
- def hide_bcrypt(val, max_len = 200)
655
+ def hide_bcrypt(val, is_xml = nil, max_len = 200)
655
656
  if is_bcrypt?(val)
656
657
  '(hidden)'
657
658
  else
658
659
  if val.is_a?(String)
659
- if (val = val.dup.strip).length > max_len
660
+ val = val.dup.force_encoding('UTF-8').strip
661
+ return CGI.escapeHTML(val) if is_xml
662
+
663
+ if val.length > max_len
660
664
  if val[0] == '<' # Seems to be HTML?
661
665
  cur_len = 0
662
666
  cur_idx = 0
@@ -703,7 +707,6 @@ def hide_bcrypt(val, max_len = 200)
703
707
  end
704
708
  val = \"#\{val}...\"
705
709
  end
706
- val = val.dup.force_encoding('UTF-8') unless val.encoding.name == 'UTF-8'
707
710
  val
708
711
  else
709
712
  val.to_s
@@ -768,7 +771,7 @@ def display_value(col_type, val)
768
771
  display_binary(val) if val
769
772
  else
770
773
  if col_type
771
- hide_bcrypt(val)
774
+ hide_bcrypt(val, col_type == :xml)
772
775
  else
773
776
  '?'
774
777
  end
@@ -1439,7 +1442,7 @@ end
1439
1442
  when :string, :text %>
1440
1443
  <% if is_bcrypt?(val) # || .readonly?
1441
1444
  is_revert = false %>
1442
- <%= hide_bcrypt(val, 1000) %>
1445
+ <%= hide_bcrypt(val, nil, 1000) %>
1443
1446
  <% else %>
1444
1447
  <%= f.text_field(k.to_sym, html_options) %>
1445
1448
  <% end %>
@@ -1476,6 +1479,13 @@ end
1476
1479
  end %>
1477
1480
  <% when :primary_key
1478
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>
1479
1489
  <% else %>
1480
1490
  <%= is_revert = false
1481
1491
  display_value(col_type, val).html_safe %>
@@ -1579,6 +1589,35 @@ flatpickr(\".timepicker\", {enableTime: true, noCalendar: true});
1579
1589
  <link rel=\"stylesheet\" type=\"text/css\" href=\"https://cdnjs.cloudflare.com/ajax/libs/slim-select/1.27.1/slimselect.min.css\">
1580
1590
  <% end %>
1581
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
+
1582
1621
  <% if true # @_brick_erd
1583
1622
  %>
1584
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
- relation = ::Brick.relations.fetch(rel_name || args.first.table_name, nil)
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}"
@@ -5,7 +5,7 @@ module Brick
5
5
  module VERSION
6
6
  MAJOR = 1
7
7
  MINOR = 0
8
- TINY = 112
8
+ TINY = 113
9
9
 
10
10
  # PRE is nil unless it's a pre-release (beta, RC, etc.)
11
11
  PRE = nil
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
- # %%% Was: ::Rails.application.routes.named_routes.route_defined?(:brick_status_path)
658
- unless ::Rails.application.routes.named_routes.names.include?(:brick_status)
659
- path_prefix = ::Brick.config.path_prefix
660
- existing_controllers = routes.each_with_object({}) do |r, s|
661
- c = r.defaults[:controller]
662
- s[c] = nil if c
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
- ::Rails.application.routes.append do
665
- tables = []
666
- views = []
667
- table_class_length = 38 # Length of "Classes that can be built from tables:"
668
- view_class_length = 37 # Length of "Classes that can be built from views:"
669
-
670
- brick_namespace_create = lambda do |path_names, res_name, options|
671
- if path_names&.present?
672
- if (path_name = path_names.pop).is_a?(Array)
673
- module_name = path_name[1]
674
- path_name = path_name.first
675
- end
676
- send(:scope, { module: module_name || path_name, path: path_name, as: path_name }) do
677
- brick_namespace_create.call(path_names, res_name, options)
678
- end
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
- send(:resources, res_name.to_sym, **options)
681
- end
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
- # %%% TODO: If no auto-controllers then enumerate the controllers folder in order to build matching routes
685
- # If auto-controllers and auto-models are both enabled then this makes sense:
686
- controller_prefix = (path_prefix ? "#{path_prefix}/" : '')
687
- sti_subclasses = ::Brick.config.sti_namespace_prefixes.each_with_object(Hash.new { |h, k| h[k] = [] }) do |v, s|
688
- # Turn something like {"::Spouse"=>"Person", "::Friend"=>"Person"} into {"Person"=>["Spouse", "Friend"]}
689
- s[v.last] << v.first[2..-1] unless v.first.end_with?('::')
690
- end
691
- versioned_views = {} # Track which views have already been done for each api_root
692
- ::Brick.relations.each do |k, v|
693
- if (schema_name = v.fetch(:schema, nil))
694
- schema_prefix = "#{schema_name}."
695
- end
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
- next if !(resource_name = v.fetch(:resource, nil)) ||
698
- existing_controllers.key?(controller_name = (
699
- resource_name = "#{schema_prefix&.tr('.', '/')}#{resource_name}"
700
- ).pluralize)
701
-
702
- object_name = k.split('.').last # Take off any first schema part
703
-
704
- full_schema_prefix = if (aps = v.fetch(:auto_prefixed_schema, nil))
705
- aps = aps[0..-2] if aps[-1] == '_'
706
- (schema_prefix&.dup || +'') << "#{aps}."
707
- else
708
- schema_prefix
709
- end
710
-
711
- # Track routes being built
712
- if (class_name = v.fetch(:class_name, nil))
713
- if v.key?(:isView)
714
- view_class_length = class_name.length if class_name.length > view_class_length
715
- views
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
- table_class_length = class_name.length if class_name.length > table_class_length
718
- tables
719
- end << [class_name, aps, resource_name]
720
- end
721
-
722
- options = {}
723
- options[:only] = [:index, :show] if v.key?(:isView)
724
-
725
- # First do the normal routes
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
- # Now the API routes if necessary
736
- full_resource = nil
737
- ::Brick.api_roots&.each do |api_root|
738
- api_done_views = (versioned_views[api_root] ||= {})
739
- found = nil
740
- test_ver_num = nil
741
- view_relation = nil
742
- # If it's a view then see if there's a versioned one available by searching for resource names
743
- # versioned with the closest number (equal to or less than) compared with our API version number.
744
- if v.key?(:isView)
745
- if (ver = object_name.match(/^v([\d_]*)/)&.captures&.first) && ver[-1] == '_'
746
- core_object_name = object_name[ver.length + 1..-1]
747
- next if api_done_views.key?(unversioned = "#{schema_prefix}v_#{core_object_name}")
748
-
749
- # Expect that the last item in the path generally holds versioning information
750
- api_ver = api_root.split('/')[-1]&.gsub('_', '.')
751
- vn_idx = api_ver.rindex(/[^\d._]/) # Position of the first numeric digit at the end of the version number
752
- # Was: .to_d
753
- 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
754
- # puts [api_ver, vn_idx, api_ver_num, unversioned].inspect
755
-
756
- next if ver.to_i > api_ver_num # Don't surface any newer views in an older API
757
-
758
- test_ver_num -= 1 until test_ver_num.zero? ||
759
- (view_relation = ::Brick.relations.fetch(
760
- found = "#{schema_prefix}v#{test_ver_num}_#{core_object_name}", nil
761
- ))
762
- api_done_views[unversioned] = nil # Mark that for this API version this view is done
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
- no_prefix_name = "#{schema_prefix}#{core_object_name}"
776
- unversioned = "#{schema_prefix}#{standard_prefix}#{::Brick.config.api_add_view_prefix}#{core_object_name}"
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
- unversioned = k
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
- view_relation ||= ::Brick.relations.fetch(found = unversioned, nil) ||
782
- (no_v_prefix_name && ::Brick.relations.fetch(found = no_v_prefix_name, nil)) ||
783
- (no_prefix_name && ::Brick.relations.fetch(found = no_prefix_name, nil))
784
- if view_relation
785
- actions = view_relation.key?(:isView) ? [:index, :show] : ::Brick::ALL_API_ACTIONS # By default all actions are allowed
786
- # Call proc that limits which endpoints get surfaced based on version, table or view name, method (get list / get one / post / patch / delete)
787
- # Returning nil makes it do nothing, false makes it skip creating this endpoint, and an array of up to
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
- if proc_result&.present?
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
- (view_relation[:api][api_ver_num] ||= {})[unversioned] = actions # Add to the list of API paths this resource responds to
833
-
834
- # view_ver_num = if (first_part = k.split('_').first) =~ /^v[\d_]+/
835
- # first_part[1..-1].gsub('_', '.').to_i
836
- # end
837
- controller_name = if (last = view_relation.fetch(:resource, nil)&.pluralize)
838
- "#{full_schema_prefix}#{last}"
839
- else
840
- found
841
- end.tr('.', '/')
842
-
843
- { :index => 'get', :create => 'post' }.each do |action, method|
844
- if actions.include?(action)
845
- # Normally goes to something like: /api/v1/employees
846
- send(method, "#{api_root}#{unversioned.tr('.', '/')}", { to: "#{controller_prefix}#{controller_name}##{action}" })
847
- end
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
- # %%% We do not yet surface the #show action
850
- if (id_col = view_relation[:pk]&.first) # ID-dependent stuff
851
- { :update => ['put', 'patch'], :destroy => ['delete'] }.each do |action, methods|
852
- if actions.include?(action)
853
- methods.each do |method|
854
- send(method, "#{api_root}#{unversioned.tr('.', '/')}/:#{id_col}", { to: "#{controller_prefix}#{controller_name}##{action}" })
855
- end
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
- if ::Brick.config.add_status && instance_variable_get(:@set).named_routes.names.exclude?(:brick_status)
864
- get("/#{controller_prefix}brick_status", to: 'brick_gem#status', as: 'brick_status')
865
- end
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
- if ::Brick.config.add_orphans && instance_variable_get(:@set).named_routes.names.exclude?(:brick_orphans)
868
- get("/#{controller_prefix}brick_orphans", to: 'brick_gem#orphans', as: 'brick_orphans')
869
- end
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
- if instance_variable_get(:@set).named_routes.names.exclude?(:brick_crosstab)
872
- get("/#{controller_prefix}brick_crosstab", to: 'brick_gem#crosstab', as: 'brick_crosstab')
873
- get("/#{controller_prefix}brick_crosstab/data", to: 'brick_gem#crosstab_data')
874
- end
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
- unless ::Brick.routes_done
877
- if Object.const_defined?('Rswag::Ui')
878
- rswag_path = ::Rails.application.routes.routes.find { |r| r.app.app == Rswag::Ui::Engine }&.instance_variable_get(:@path_formatter)&.instance_variable_get(:@parts)&.join
879
- first_endpoint_parts = nil
880
- (doc_endpoints = Rswag::Ui.config.config_object[:urls])&.each do |doc_endpoint|
881
- puts "Mounting OpenApi 3.0 documentation endpoint for \"#{doc_endpoint[:name]}\" on #{doc_endpoint[:url]}"
882
- send(:get, doc_endpoint[:url], { to: 'brick_openapi#index' })
883
- endpoint_parts = doc_endpoint[:url]&.split('/')
884
- first_endpoint_parts ||= endpoint_parts
885
- end
886
- if doc_endpoints.present?
887
- if rswag_path && first_endpoint_parts
888
- puts "API documentation now available when navigating to: /#{first_endpoint_parts&.find(&:present?)}/index.html"
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
- sample_path = rswag_path || '/api-docs'
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 "Brick: rswag-ui gem detected -- to make OpenAPI 3.0 documentation available from a path such as '#{sample_path}/v1/swagger.json',"
897
- puts ' put code such as this in an initializer:'
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
- ::Brick.routes_done = true
910
- puts "\n" if tables.present? || views.present?
911
- if tables.present?
912
- puts "Classes that can be built from tables:#{' ' * (table_class_length - 38)} Path:"
913
- puts "======================================#{' ' * (table_class_length - 38)} ====="
914
- ::Brick.display_classes(controller_prefix, tables, table_class_length)
915
- end
916
- if views.present?
917
- puts "Classes that can be built from views:#{' ' * (view_class_length - 37)} Path:"
918
- puts "=====================================#{' ' * (view_class_length - 37)} ====="
919
- ::Brick.display_classes(controller_prefix, views, view_class_length)
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.112
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-14 00:00:00.000000000 Z
11
+ date: 2023-02-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord