brick 1.0.244 → 1.0.246
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 +66 -59
- data/lib/brick/rails/engine.rb +76 -72
- data/lib/brick/rails/form_tags.rb +25 -14
- data/lib/brick/rails.rb +1 -1
- data/lib/brick/reflect_tables.rb +1 -2
- data/lib/brick/version_number.rb +1 -1
- metadata +3 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3410ae5fca9b12aa31007df9d3fac95a39f09eee58f4ffc2089bada97bde7793
|
|
4
|
+
data.tar.gz: 0da56c9311d8dd0ce2fd3a05039a6f85ca9910c64b303c25fc26f8d65fab512b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7a2e821dfee25a5df265caf5700e25003cbc7cab88e439102fc949f5dfbba2f9f7b73803c98068d373ffbf12cab27dac3859c76a7772ea19bbaf4ffdbfbddbe6
|
|
7
|
+
data.tar.gz: 701d6d9e7d374cbe850806ce732f5b765c1ea3d051c111f316bcd29fdf45622d8999c04fa89ca058f13052670f56c77350fde24e00139ef40dc892b0c97ca896
|
data/lib/brick/extensions.rb
CHANGED
|
@@ -162,7 +162,7 @@ module ActiveRecord
|
|
|
162
162
|
def _brick_deserialized_id(obj, id_col)
|
|
163
163
|
id = []
|
|
164
164
|
self._pk_as_array.each_with_index do |pk_part, idx|
|
|
165
|
-
id << if
|
|
165
|
+
id << if (id_sym = id_col[idx]&.to_sym) && obj.respond_to?(id_sym)
|
|
166
166
|
self._brick_deserialized_value(obj, [[pk_part, id_col[idx]]])&.first
|
|
167
167
|
else
|
|
168
168
|
id_col[idx]
|
|
@@ -926,11 +926,13 @@ module ActiveRecord
|
|
|
926
926
|
poly_ft = [hm.source_reflection.inverse_of.foreign_type, hmt_assoc.source_reflection.class_name]
|
|
927
927
|
end
|
|
928
928
|
# link_back << hm.source_reflection.inverse_of.name
|
|
929
|
-
while hmt_assoc.options[:through] && (hmt_assoc = klass.reflect_on_association(hmt_assoc.options[:through]))
|
|
929
|
+
while hmt_assoc.options[:through] && (hmt_assoc = klass.reflect_on_association(xy = hmt_assoc.options[:through]))
|
|
930
|
+
if hmt_assoc.macro == :has_and_belongs_to_many
|
|
931
|
+
through_sources.unshift(hmt_assoc)
|
|
932
|
+
link_back << hmt_assoc.source_reflection.klass.reflect_on_all_associations.find { |a| a.macro == :has_and_belongs_to_many && a.join_table == hmt_assoc.join_table }.name
|
|
933
|
+
end
|
|
930
934
|
through_sources.unshift(hmt_assoc)
|
|
931
935
|
end
|
|
932
|
-
# Turn the last member of link_back into a foreign key
|
|
933
|
-
link_back << hmt_assoc.source_reflection.foreign_key
|
|
934
936
|
# If it's a HMT based on a HM -> HM, must JOIN the last table into the mix at the end
|
|
935
937
|
this_hm = hm
|
|
936
938
|
while !(src_ref = this_hm.source_reflection).belongs_to? && (thr = src_ref.options[:through])
|
|
@@ -940,39 +942,48 @@ module ActiveRecord
|
|
|
940
942
|
from_clause = +"#{_br_quoted_name(through_sources.first.table_name)} br_t0"
|
|
941
943
|
# ActiveStorage will not get the correct count unless we do some extra filtering later
|
|
942
944
|
tbl_nm = 'br_t0' if Object.const_defined?('ActiveStorage') && through_sources.first.klass <= ::ActiveStorage::Attachment
|
|
943
|
-
|
|
944
|
-
|
|
945
|
+
# Turn the last member of link_back into a foreign key
|
|
946
|
+
link_back << ((tsf = through_sources.shift).macro == :has_and_belongs_to_many ?
|
|
947
|
+
tsf.klass.primary_key : hmt_assoc.source_reflection.foreign_key)
|
|
948
|
+
fk_col = tsf.macro == :has_and_belongs_to_many ?
|
|
949
|
+
tsf.klass.primary_key : tsf.foreign_key
|
|
945
950
|
idx = 0
|
|
946
951
|
bail_out = nil
|
|
947
952
|
the_chain = through_sources.map do |a|
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
"br_t#{idx
|
|
953
|
+
puts "#{a.name} - #{a.macro}"
|
|
954
|
+
if a.macro == :has_and_belongs_to_many
|
|
955
|
+
from_clause << "\n LEFT OUTER JOIN #{a.join_table} br_t#{idx += 1} ON br_t#{idx}.#{a.association_foreign_key} = br_t#{idx - 1}.#{a.active_record.primary_key}"
|
|
956
|
+
from_clause << "\n LEFT OUTER JOIN #{a.active_record.table_name} br_t#{idx += 1} ON br_t#{idx}.#{a.active_record.primary_key} = br_t#{idx - 1}.#{a.foreign_key}"
|
|
957
|
+
else
|
|
958
|
+
from_clause << "\n LEFT OUTER JOIN #{a.table_name} br_t#{idx += 1} "
|
|
959
|
+
from_clause << if (src_ref = a.source_reflection).macro == :belongs_to
|
|
960
|
+
link_back << (nm = hmt_assoc.source_reflection.inverse_of&.name)
|
|
961
|
+
# puts "BT #{a.table_name}"
|
|
962
|
+
"ON br_t#{idx}.#{a.active_record.primary_key} = br_t#{idx - 1}.#{a.foreign_key}"
|
|
963
|
+
elsif src_ref.options[:as]
|
|
964
|
+
"ON br_t#{idx}.#{src_ref.type} = '#{src_ref.active_record.name}'" + # "polymorphable_type"
|
|
965
|
+
" AND br_t#{idx}.#{src_ref.foreign_key} = br_t#{idx - 1}.id"
|
|
966
|
+
elsif src_ref.options[:source_type]
|
|
967
|
+
if a == hm.source_reflection
|
|
968
|
+
print "Skipping #{hm.name} --HMT-> #{hm.source_reflection.name} as it uses source_type in a way which is not yet supported"
|
|
969
|
+
nix << k
|
|
970
|
+
bail_out = true
|
|
971
|
+
break
|
|
972
|
+
# "ON br_t#{idx}.#{a.foreign_type} = '#{src_ref.options[:source_type]}' AND " \
|
|
973
|
+
# "br_t#{idx}.#{a.foreign_key} = br_t#{idx - 1}.#{a.active_record.primary_key}"
|
|
974
|
+
else # Works for HMT through a polymorphic HO
|
|
975
|
+
link_back << hmt_assoc.source_reflection.inverse_of&.name # Some polymorphic "_able" thing
|
|
976
|
+
"ON br_t#{idx - 1}.#{a.foreign_type} = '#{src_ref.options[:source_type]}' AND " \
|
|
977
|
+
"br_t#{idx - 1}.#{a.foreign_key} = br_t#{idx}.#{a.active_record.primary_key}"
|
|
978
|
+
end
|
|
979
|
+
else # Standard has_many or has_one
|
|
980
|
+
# puts "HM #{a.table_name}"
|
|
981
|
+
nm = hmt_assoc.source_reflection.inverse_of&.name
|
|
982
|
+
# binding.pry unless nm
|
|
983
|
+
link_back << nm # if nm
|
|
984
|
+
"ON br_t#{idx}.#{a.foreign_key} = br_t#{idx - 1}.#{a.active_record.primary_key}"
|
|
968
985
|
end
|
|
969
|
-
|
|
970
|
-
# puts "HM #{a.table_name}"
|
|
971
|
-
nm = hmt_assoc.source_reflection.inverse_of&.name
|
|
972
|
-
# binding.pry unless nm
|
|
973
|
-
link_back << nm # if nm
|
|
974
|
-
"ON br_t#{idx}.#{a.foreign_key} = br_t#{idx - 1}.#{a.active_record.primary_key}"
|
|
975
|
-
end
|
|
986
|
+
end
|
|
976
987
|
link_back.unshift(a.source_reflection.name)
|
|
977
988
|
[a.table_name, a.foreign_key, a.source_reflection.macro]
|
|
978
989
|
end
|
|
@@ -980,7 +991,9 @@ module ActiveRecord
|
|
|
980
991
|
|
|
981
992
|
# puts "LINK BACK! #{k} : #{hm.table_name} #{link_back.map(&:to_s).join('.')}"
|
|
982
993
|
# count_column is determined from the originating HMT member
|
|
983
|
-
if
|
|
994
|
+
if hmt_assoc.macro == :has_and_belongs_to_many
|
|
995
|
+
"br_t#{idx}.#{src_ref.active_record.primary_key}"
|
|
996
|
+
elsif (src_ref = hm.source_reflection).nil?
|
|
984
997
|
puts "*** Warning: Could not determine destination model for this HMT association in model #{klass.name}:\n has_many :#{hm.name}, through: :#{hm.options[:through]}"
|
|
985
998
|
puts
|
|
986
999
|
nix << k
|
|
@@ -2162,7 +2175,9 @@ class Object
|
|
|
2162
2175
|
# (More information on https://docs.avohq.io/3.0/controllers.html)
|
|
2163
2176
|
controller_base = Avo::ResourcesController
|
|
2164
2177
|
end
|
|
2165
|
-
if
|
|
2178
|
+
if model && !(model < ActiveRecord::Base)
|
|
2179
|
+
raise "Your project defines class \"#{model.name}\" which is not an ActiveRecord model. If some other model class for this resource exists that can be used instead, you can configure a Brick table_name_prefix in order to have a specific table name refer to that class."
|
|
2180
|
+
elsif !model&.table_exists? && (tn = model&.table_name)
|
|
2166
2181
|
msg = +"Can't find table \"#{tn}\" for model #{model.name}."
|
|
2167
2182
|
puts
|
|
2168
2183
|
# Potential bad inflection?
|
|
@@ -2706,7 +2721,6 @@ class Object
|
|
|
2706
2721
|
# ActiveRecord::Base.execute_sql("SET SEARCH_PATH = ?;", schema)
|
|
2707
2722
|
# end
|
|
2708
2723
|
|
|
2709
|
-
is_need_params = true
|
|
2710
2724
|
code << " def edit\n"
|
|
2711
2725
|
code << " #{find_by_name}\n"
|
|
2712
2726
|
code << " end\n"
|
|
@@ -2799,7 +2813,7 @@ class Object
|
|
|
2799
2813
|
end
|
|
2800
2814
|
end
|
|
2801
2815
|
|
|
2802
|
-
code << "private\n"
|
|
2816
|
+
code << "private\n"
|
|
2803
2817
|
|
|
2804
2818
|
if pk.present?
|
|
2805
2819
|
code << " def #{find_obj}
|
|
@@ -2829,29 +2843,23 @@ class Object
|
|
|
2829
2843
|
private find_obj
|
|
2830
2844
|
end
|
|
2831
2845
|
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
code << " params.require(:#{require_txt
|
|
2846
|
-
}).permit(#{permits_txt.map(&:inspect).join(', ')})\n"
|
|
2847
|
-
code << " end\n"
|
|
2848
|
-
self.define_method(params_name) do
|
|
2849
|
-
params.require(model.base_class.name.underscore.tr('/', '_').to_sym).permit(permits)
|
|
2850
|
-
end
|
|
2846
|
+
code << " def #{params_name}\n"
|
|
2847
|
+
require_txt = model.base_class.name.underscore.tr('/', '_')
|
|
2848
|
+
is_for_expects = ::ActiveSupport.version >= ::Gem::Version.new('8.0a')
|
|
2849
|
+
permits_txt = model._brick_find_permits(model, permits = model._brick_all_fields(true), is_for_expects)
|
|
2850
|
+
if is_for_expects
|
|
2851
|
+
code << " params.expect(#{require_txt}: #{permits_txt})\n"
|
|
2852
|
+
self.define_method(params_name) do
|
|
2853
|
+
params.expect({ model.base_class.name.underscore.tr('/', '_').to_sym => permits })
|
|
2854
|
+
end
|
|
2855
|
+
else
|
|
2856
|
+
code << " params.require(:#{require_txt}).permit(#{permits_txt.map(&:inspect).join(', ')})\n"
|
|
2857
|
+
self.define_method(params_name) do
|
|
2858
|
+
params.require(model.base_class.name.underscore.tr('/', '_').to_sym).permit(permits)
|
|
2851
2859
|
end
|
|
2852
|
-
private params_name
|
|
2853
|
-
# Get column names for params from relations[model.table_name][:cols].keys
|
|
2854
2860
|
end
|
|
2861
|
+
code << " end\n"
|
|
2862
|
+
private params_name
|
|
2855
2863
|
end # unless is_openapi
|
|
2856
2864
|
code << "end # #{class_name}\n"
|
|
2857
2865
|
end # class definition
|
|
@@ -3210,7 +3218,6 @@ module Brick
|
|
|
3210
3218
|
end
|
|
3211
3219
|
end
|
|
3212
3220
|
abstract_activerecord_bases = ::Brick.eager_load_classes(true)
|
|
3213
|
-
rails_root = ::Rails.root.to_s
|
|
3214
3221
|
models = ::Brick.relations.each_with_object({}) do |rel, s|
|
|
3215
3222
|
next if rel.first.is_a?(Symbol)
|
|
3216
3223
|
|
data/lib/brick/rails/engine.rb
CHANGED
|
@@ -324,7 +324,7 @@ function linkSchemas() {
|
|
|
324
324
|
end
|
|
325
325
|
end
|
|
326
326
|
end
|
|
327
|
-
"<script
|
|
327
|
+
"<script<%= @_request.env['_brick_nonce'] %>>
|
|
328
328
|
#{JS_CHANGEOUT}
|
|
329
329
|
document.addEventListener(\"turbo:render\", linkSchemas);
|
|
330
330
|
window.addEventListener(\"popstate\", linkSchemas);
|
|
@@ -826,56 +826,51 @@ window.addEventListener(\"popstate\", linkSchemas);
|
|
|
826
826
|
['Crosstab', is_crosstab]].each do |table_option, show_it|
|
|
827
827
|
table_options << "<option value=\"#{prefix}brick_#{table_option.downcase}\">(#{table_option})</option>".html_safe if show_it
|
|
828
828
|
end
|
|
829
|
-
css = +"
|
|
830
|
-
|
|
829
|
+
css = +"
|
|
830
|
+
<%
|
|
831
|
+
if @_request.respond_to?(:content_security_policy) && (csp = @_request.content_security_policy)&.directives&.present?
|
|
832
|
+
@_request.env['_is_brick'] = true
|
|
833
|
+
if @_request.respond_to?(:content_security_policy_nonce_directives)
|
|
834
|
+
@_request.content_security_policy_nonce_directives = %w[ script-src ]
|
|
835
|
+
@_request.env['_brick_nonce'] = \" nonce=\\\"#\{@_request.content_security_policy_nonce}\\\"\".html_safe
|
|
836
|
+
%><meta name=\"csp-nonce\" content=\"<%= @_request.content_security_policy_nonce %>\"><%
|
|
837
|
+
end
|
|
838
|
+
if !@_request.respond_to?(:_brick_content_security_policy)
|
|
839
|
+
if csp.instance_variables.exclude?(:@_brick_style_shas)
|
|
840
|
+
csp.instance_variable_set(:@_brick_style_shas, [
|
|
841
|
+
\"'sha256-#\{Base64.encode64(Digest.const_get(:SHA256).digest(::Brick::Rails::BRICK_CSS)).chomp}'\",
|
|
842
|
+
\"'sha256-#\{Base64.encode64(Digest.const_get(:SHA256).digest(::Brick::Rails::IN_APP_STYLE)).chomp}'\",
|
|
843
|
+
\"'sha256-y+oXtN5Bag5VRQgH6D87Eo4UdOZOJiqg31ZNfDibDwM='\", # SHA for the text_field used in brick_field ('min-width: 154px;field-sizing: content;')
|
|
844
|
+
\"'sha256-aOKu38ec/bSbd1BWfOZWow6kP78MsLOsTmNyCpYqsXM='\", # SHA for Mermaid ('font-family: Arial')
|
|
845
|
+
\"'sha256-P8hbc8HpnNaBWbGVqO8n4uIP3lIM4rGog3PnEYWwrzQ='\" # SHA for flatpickr calendar ('.flatpickr-calendar {background: #A0FFA0;}')
|
|
846
|
+
# \"'sha256-oU3/kVZLL/AmlO0Oi4iZplNUwV9XJW7qt6J9Mm2ASNs='\" # SHA for Mermaid (SVG things)
|
|
847
|
+
])
|
|
848
|
+
end
|
|
849
|
+
|
|
850
|
+
::ActionDispatch::ContentSecurityPolicy::Request.module_exec do
|
|
851
|
+
alias :_brick_content_security_policy :content_security_policy
|
|
852
|
+
def content_security_policy
|
|
853
|
+
return _brick_content_security_policy if env['_is_brick'].blank?
|
|
854
|
+
|
|
855
|
+
csp = ::ActionDispatch::ContentSecurityPolicy.new
|
|
856
|
+
csp.directives.merge! ({
|
|
857
|
+
'style-src': [\"'self'\", 'https://cdn.jsdelivr.net', \"'unsafe-hashes'\", \"'nonce-#\{content_security_policy_nonce}'\"] +
|
|
858
|
+
_brick_content_security_policy.instance_variable_get(:@_brick_style_shas),
|
|
859
|
+
'script-src': [\"'self'\", 'https://cdn.jsdelivr.net', 'https://apis.google.com', 'https://accounts.google.com', \"'nonce-#\{content_security_policy_nonce}'\"],
|
|
860
|
+
'connect-src': [\"'self'\", 'https://cdn.jsdelivr.net']
|
|
861
|
+
})
|
|
862
|
+
csp
|
|
863
|
+
end
|
|
864
|
+
end
|
|
865
|
+
end
|
|
866
|
+
end %>
|
|
867
|
+
<style>#{::Brick::Rails::BRICK_CSS}</style>
|
|
868
|
+
<script<%= @_request.env['_brick_nonce'] %>>
|
|
831
869
|
if (window.history.state && window.history.state.turbo)
|
|
832
870
|
window.addEventListener(\"popstate\", function () { location.reload(true); });
|
|
833
871
|
</script>
|
|
834
872
|
|
|
835
873
|
<%
|
|
836
|
-
if @_request.respond_to?(:content_security_policy)
|
|
837
|
-
@_request.env['_is_brick'] = true
|
|
838
|
-
if (csp = @_request.content_security_policy).instance_variables.exclude?(:@_brick_style_shas)
|
|
839
|
-
csp.instance_variable_set(:@_brick_style_shas, [
|
|
840
|
-
\"'sha256-#\{Base64.encode64(Digest.const_get(:SHA256).digest(::Brick::Rails::BRICK_CSS)).chomp}'\",
|
|
841
|
-
\"'sha256-#\{Base64.encode64(Digest.const_get(:SHA256).digest(::Brick::Rails::IN_APP_STYLE)).chomp}'\"
|
|
842
|
-
])
|
|
843
|
-
end
|
|
844
|
-
if !@_request.respond_to?(:_brick_content_security_policy)
|
|
845
|
-
::ActionDispatch::ContentSecurityPolicy::Request.module_exec do
|
|
846
|
-
alias :_brick_content_security_policy :content_security_policy
|
|
847
|
-
def content_security_policy
|
|
848
|
-
# Add appropriate hashes for inline styles to the content-security-policy if needed
|
|
849
|
-
if (cspd = (csp = _brick_content_security_policy).directives.fetch('style-src', nil)) && env['_is_brick']
|
|
850
|
-
cspd.select! { |val| val == \"'self'\" }
|
|
851
|
-
if params['action'] == 'show'
|
|
852
|
-
cspd << \"'unsafe-inline'\"
|
|
853
|
-
else
|
|
854
|
-
csp.instance_variable_get(:@_brick_style_shas).each { |s| cspd << s }
|
|
855
|
-
cspd << \"'unsafe-hashes'\"
|
|
856
|
-
end
|
|
857
|
-
cspd << 'https://cdn.jsdelivr.net'
|
|
858
|
-
end
|
|
859
|
-
if (cspsd = csp.directives.fetch('script-src', nil))
|
|
860
|
-
cspsd.select! { |val| val == \"'self'\" }
|
|
861
|
-
cspsd << \"'unsafe-inline'\"
|
|
862
|
-
cspsd << 'https://cdn.jsdelivr.net'
|
|
863
|
-
end
|
|
864
|
-
if (cspcd = csp.directives.fetch('connect-src', nil))
|
|
865
|
-
cspcd.select! { |val| val == \"'self'\" }
|
|
866
|
-
cspcd << 'https://cdn.jsdelivr.net'
|
|
867
|
-
end
|
|
868
|
-
csp
|
|
869
|
-
end
|
|
870
|
-
|
|
871
|
-
alias :_brick_content_security_policy_nonce :content_security_policy_nonce
|
|
872
|
-
def content_security_policy_nonce
|
|
873
|
-
_brick_content_security_policy_nonce unless env['_is_brick']
|
|
874
|
-
end
|
|
875
|
-
end
|
|
876
|
-
end
|
|
877
|
-
end
|
|
878
|
-
|
|
879
874
|
# Accommodate composite primary keys that include strings with forward-slash characters
|
|
880
875
|
def slashify(*vals)
|
|
881
876
|
vals.map { |val_part| val_part.is_a?(String) ? val_part.gsub('/', '^^sl^^') : val_part }
|
|
@@ -890,7 +885,11 @@ callbacks = {} %>"
|
|
|
890
885
|
poly_cols << @_brick_model.brick_foreign_type(v[1].first)
|
|
891
886
|
v.last[1].each_with_object([]) { |x, s| s << "[#{x.name}, #{x.primary_key.inspect}]" }.join(', ')
|
|
892
887
|
else
|
|
893
|
-
|
|
888
|
+
# If the BT association specifies a column for the primary_key, use that ...
|
|
889
|
+
fm_pk = @_brick_model.reflect_on_association(v.last.first)&.options&.[](:primary_key)&.to_s ||
|
|
890
|
+
# ... otherwise, use the model's primary_key.
|
|
891
|
+
(v.last[1].primary_key.present? && v.last[1].primary_key)
|
|
892
|
+
"[#{v.last[1].name}, #{fm_pk.inspect}]"
|
|
894
893
|
end
|
|
895
894
|
s << "#{v.first.inspect} => [#{v.last.first.inspect}, [#{foreign_models}], #{v.last[2].inspect}]"
|
|
896
895
|
end
|
|
@@ -902,7 +901,7 @@ callbacks = {} %>"
|
|
|
902
901
|
end
|
|
903
902
|
|
|
904
903
|
# %%% When doing schema select, if we're on a new page go to index
|
|
905
|
-
script = "<script
|
|
904
|
+
script = "<script<%= @_request.env['_brick_nonce'] %>>
|
|
906
905
|
// Add \"Are you sure?\" behaviour to any data-confirm buttons out there
|
|
907
906
|
document.querySelectorAll(\"input[type=submit][data-confirm]\").forEach(function (btn) {
|
|
908
907
|
btn.addEventListener(\"click\", function (evt) {
|
|
@@ -919,7 +918,8 @@ document.querySelectorAll(\"input[type=submit][data-confirm]\").forEach(function
|
|
|
919
918
|
"\nbrickTestSchema = \"#{::Brick.test_schema}\";" if ::Brick.test_schema
|
|
920
919
|
}
|
|
921
920
|
function doFetch(method, payload, success) {
|
|
922
|
-
payload.authenticity_token = <%=
|
|
921
|
+
payload.authenticity_token = <%=
|
|
922
|
+
(!session.respond_to?(:enabled?) || session.enabled?) ? ((session[:_csrf_token] || form_authenticity_token).inspect.html_safe) : 'null' %>;
|
|
923
923
|
var action = payload._brick_action || location.href;
|
|
924
924
|
delete payload._brick_action;
|
|
925
925
|
if (!success) {
|
|
@@ -954,7 +954,7 @@ if (window.brickFontFamily) {
|
|
|
954
954
|
<div id=\"dropper\" contenteditable=\"true\"></div>
|
|
955
955
|
<input type=\"button\" id=\"btnImport\" value=\"Import\">
|
|
956
956
|
|
|
957
|
-
<script
|
|
957
|
+
<script<%= @_request.env['_brick_nonce'] %>>
|
|
958
958
|
var dropperDiv = document.getElementById(\"dropper\");
|
|
959
959
|
var btnImport = document.getElementById(\"btnImport\");
|
|
960
960
|
var droppedTSV;
|
|
@@ -981,19 +981,6 @@ if (window.brickFontFamily) {
|
|
|
981
981
|
}
|
|
982
982
|
var sheetUrl;
|
|
983
983
|
var spreadsheetId;
|
|
984
|
-
var sheetsLink = document.getElementById(\"sheetsLink\");
|
|
985
|
-
function gapiLoaded() {
|
|
986
|
-
// Have a click on the sheets link to bring up the sign-in window. (Must happen from some kind of user click.)
|
|
987
|
-
sheetsLink.addEventListener(\"click\", async function (evt) {
|
|
988
|
-
evt.preventDefault();
|
|
989
|
-
var client = google.accounts.oauth2.initTokenClient({
|
|
990
|
-
client_id: \"487319557829-fgj4u660igrpptdji7ev0r5hb6kh05dh.apps.googleusercontent.com\",
|
|
991
|
-
scope: \"https://www.googleapis.com/auth/spreadsheets https://www.googleapis.com/auth/drive.file\",
|
|
992
|
-
callback: updateSignInStatus
|
|
993
|
-
});
|
|
994
|
-
client.requestAccessToken();
|
|
995
|
-
});
|
|
996
|
-
}
|
|
997
984
|
|
|
998
985
|
async function updateSignInStatus(token) {
|
|
999
986
|
await new Promise(function (resolve) {
|
|
@@ -1052,7 +1039,24 @@ if (window.brickFontFamily) {
|
|
|
1052
1039
|
}
|
|
1053
1040
|
</script>
|
|
1054
1041
|
<script src=\"https://apis.google.com/js/api.js\"></script>
|
|
1055
|
-
<script async defer src=\"https://accounts.google.com/gsi/client\"
|
|
1042
|
+
<script async defer src=\"https://accounts.google.com/gsi/client\" id=\"gapiScript\"<%= @_request.env['_brick_nonce'] %>></script>
|
|
1043
|
+
<script<%= @_request.env['_brick_nonce'] %>>
|
|
1044
|
+
document.getElementById(\"gapiScript\").addEventListener(\"onload\",
|
|
1045
|
+
function () { // gapiLoaded
|
|
1046
|
+
var sheetsLink = document.getElementById(\"sheetsLink\");
|
|
1047
|
+
// Have a click on the sheets link to bring up the sign-in window. (Must happen from some kind of user click.)
|
|
1048
|
+
sheetsLink.addEventListener(\"click\", async function (evt) {
|
|
1049
|
+
evt.preventDefault();
|
|
1050
|
+
var client = google.accounts.oauth2.initTokenClient({
|
|
1051
|
+
client_id: \"487319557829-fgj4u660igrpptdji7ev0r5hb6kh05dh.apps.googleusercontent.com\",
|
|
1052
|
+
scope: \"https://www.googleapis.com/auth/spreadsheets https://www.googleapis.com/auth/drive.file\",
|
|
1053
|
+
callback: updateSignInStatus
|
|
1054
|
+
});
|
|
1055
|
+
client.requestAccessToken();
|
|
1056
|
+
});
|
|
1057
|
+
}
|
|
1058
|
+
);
|
|
1059
|
+
</script>
|
|
1056
1060
|
"
|
|
1057
1061
|
end # DutyFree data export and import
|
|
1058
1062
|
# %%% Instead of our current "for Janet Leverling (Employee)" kind of link we previously had this code that did a "where x = 123" thing:
|
|
@@ -1130,7 +1134,7 @@ end
|
|
|
1130
1134
|
<div class=\"colExclusion\"><%= excl %></div>
|
|
1131
1135
|
<% end %>
|
|
1132
1136
|
</div>
|
|
1133
|
-
<script
|
|
1137
|
+
<script<%= @_request.env['_brick_nonce'] %>>
|
|
1134
1138
|
[... document.getElementsByClassName(\"colExclusion\")].forEach(function (excl) {
|
|
1135
1139
|
excl.addEventListener(\"click\", function () {
|
|
1136
1140
|
doFetch(\"POST\", {_brick_unexclude: this.innerHTML});
|
|
@@ -1141,7 +1145,7 @@ end
|
|
|
1141
1145
|
# SEARCH BOX
|
|
1142
1146
|
if @_brick_es && @_brick_es&.index('r') # Must have at least Elasticsearch Read access %>
|
|
1143
1147
|
<input type=\"text\" id=\"esSearch\" class=\"dimmed\">
|
|
1144
|
-
<script
|
|
1148
|
+
<script<%= @_request.env['_brick_nonce'] %>>
|
|
1145
1149
|
var esSearch = document.getElementById(\"esSearch\");
|
|
1146
1150
|
var usedTerms = {};
|
|
1147
1151
|
var isEsFiltered = false;
|
|
@@ -1327,7 +1331,7 @@ end
|
|
|
1327
1331
|
kls = Object.const_get((rel = ::Brick.relations.fetch(r[0], nil))&.fetch(:class_name, nil))
|
|
1328
1332
|
rescue
|
|
1329
1333
|
end
|
|
1330
|
-
if kls.is_a?(Class) && (path_helper = respond_to?(bi_path = \"#\{kls._brick_index}_path\".to_sym) ? bi_path : nil)
|
|
1334
|
+
if kls.is_a?(Class) && kls.respond_to?(:_brick_index) && (path_helper = respond_to?(bi_path = \"#\{kls._brick_index}_path\".to_sym) ? bi_path : nil)
|
|
1331
1335
|
link_to(r[0], send(path_helper))
|
|
1332
1336
|
else
|
|
1333
1337
|
r[0]
|
|
@@ -1504,7 +1508,7 @@ end
|
|
|
1504
1508
|
end
|
|
1505
1509
|
s << "<table id=\"#{hm_name}\" class=\"shadow\">
|
|
1506
1510
|
<tr><th>#{hm[1]}#{' poly' if hm[0].options[:as]} #{hm[3]}
|
|
1507
|
-
<% if predicates && respond_to?(:new_#{partial_new_path_name = hm.first.klass._brick_index(:singular)}_path) %>
|
|
1511
|
+
<% if defined?(predicates) && predicates && respond_to?(:new_#{partial_new_path_name = hm.first.klass._brick_index(:singular)}_path) %>
|
|
1508
1512
|
<span class = \"add-hm-related\"><%=
|
|
1509
1513
|
pk_val = (obj_pk = model.primary_key).is_a?(String) ? obj.send(obj_pk) : obj_pk.map { |pk_part| obj.send(pk_part) }
|
|
1510
1514
|
pk_val_arr = [pk_val] unless pk_val.is_a?(Array)
|
|
@@ -1590,7 +1594,7 @@ end}
|
|
|
1590
1594
|
}
|
|
1591
1595
|
</style>
|
|
1592
1596
|
<script src=\"https://cdn.jsdelivr.net/npm/flatpickr\"></script>
|
|
1593
|
-
<script
|
|
1597
|
+
<script<%= @_request.env['_brick_nonce'] %>>
|
|
1594
1598
|
flatpickr(\".datepicker\");
|
|
1595
1599
|
flatpickr(\".datetimepicker\", {enableTime: true});
|
|
1596
1600
|
flatpickr(\".timepicker\", {enableTime: true, noCalendar: true});
|
|
@@ -1611,7 +1615,7 @@ flatpickr(\".timepicker\", {enableTime: true, noCalendar: true});
|
|
|
1611
1615
|
# Uncaught TypeError: Failed to resolve module specifier \"immutable-json-patch\". Relative references must start with either \"/\", \"./\", or \"../\".
|
|
1612
1616
|
if @_json_fields_present %>
|
|
1613
1617
|
<link rel=\"stylesheet\" type=\"text/css\" href=\"https://cdn.jsdelivr.net/npm/vanilla-jsoneditor@0.19.0/themes/jse-theme-default.min.css\">
|
|
1614
|
-
<script type=\"module\"
|
|
1618
|
+
<script type=\"module\"<%= @_request.env['_brick_nonce'] %>>
|
|
1615
1619
|
import { JSONEditor } from \"https://cdn.jsdelivr.net/npm/vanilla-jsoneditor@0.19.0/index.min.js\";
|
|
1616
1620
|
document.querySelectorAll(\"input.jsonpicker\").forEach(function (inp) {
|
|
1617
1621
|
var jsonDiv;
|
|
@@ -1639,7 +1643,7 @@ flatpickr(\".timepicker\", {enableTime: true, noCalendar: true});
|
|
|
1639
1643
|
|
|
1640
1644
|
<% if true # @_brick_erd
|
|
1641
1645
|
%>
|
|
1642
|
-
<script
|
|
1646
|
+
<script<%= @_request.env['_brick_nonce'] %>>
|
|
1643
1647
|
var imgErd = document.getElementById(\"imgErd\");
|
|
1644
1648
|
var mermaidErd = document.getElementById(\"mermaidErd\");
|
|
1645
1649
|
var mermaidCode;
|
|
@@ -1708,7 +1712,7 @@ flatpickr(\".timepicker\", {enableTime: true, noCalendar: true});
|
|
|
1708
1712
|
"
|
|
1709
1713
|
end
|
|
1710
1714
|
if representation == :grid
|
|
1711
|
-
inline << "<script
|
|
1715
|
+
inline << "<script<%= @_request.env['_brick_nonce'] %>>
|
|
1712
1716
|
<% # Make column headers sort when clicked
|
|
1713
1717
|
# %%% Create a smart javascript routine which can do this client-side %>
|
|
1714
1718
|
[... document.getElementsByTagName(\"TH\")].forEach(function (th) {
|
|
@@ -112,7 +112,7 @@ module Brick::Rails::FormTags
|
|
|
112
112
|
next unless klass.table_exists?
|
|
113
113
|
|
|
114
114
|
rid = pk.map { |pk_part| obj.send(pk_part.to_sym) }
|
|
115
|
-
out << "<tr x-id=\"#{rid.join('/')}\">\n"
|
|
115
|
+
out << "<tr x-id=\"#{slashed_rid = rid.join('/')}\">\n"
|
|
116
116
|
out << "<td class=\"col-sticky alternating-gray\">#{link_to('⇛', send("#{klass._brick_index(:singular)}_path".to_sym, rid),
|
|
117
117
|
{ class: 'big-arrow' })}</td>\n" if pk.present?
|
|
118
118
|
ac = obj.instance_variable_get(:@association_cache) || obj.instance_variable_set(:@association_cache, {})
|
|
@@ -134,8 +134,14 @@ module Brick::Rails::FormTags
|
|
|
134
134
|
if bt[2] && obj.respond_to?(poly_id_col = "#{bt.first}_id") # Polymorphic?
|
|
135
135
|
if (poly_id = obj.send(poly_id_col))
|
|
136
136
|
bt_class = obj.send(klass.brick_foreign_type(bt.first))
|
|
137
|
-
|
|
138
|
-
|
|
137
|
+
root_class_name = (::Brick.existing_stis[bt_class] || bt_class)
|
|
138
|
+
begin
|
|
139
|
+
base_class_underscored = root_class_name.constantize.base_class._brick_index(:singular)
|
|
140
|
+
out << link_to("#{bt_class} ##{poly_id}", send("#{base_class_underscored}_path".to_sym, poly_id))
|
|
141
|
+
rescue NameError => ee
|
|
142
|
+
puts "WARNING: While searching for a polymorphically associated #{bt.first} for the #{klass.name} with ID #{slashed_rid}, was unable to locate a model called \"#{root_class_name}\". This model might have been deleted, thereby orphaning rows in the #{klass.table_name} table."
|
|
143
|
+
out << "<span class=\"orphan\"><< Orphaned \"#{root_class_name}\" with ID: #{slashed_rid} >></span>"
|
|
144
|
+
end
|
|
139
145
|
end
|
|
140
146
|
else # BT or HOT
|
|
141
147
|
bt_class = bt[1].first.first
|
|
@@ -151,11 +157,17 @@ module Brick::Rails::FormTags
|
|
|
151
157
|
end
|
|
152
158
|
br_descrip_args = [obj]
|
|
153
159
|
br_descrip_args += [bt_class._brick_deserialized_value(obj, descrips[0..-2]), bt_id_col] if descrips
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
160
|
+
out << if bt_id_col.blank? && bt[1].first[1] # Is this a BT which references a table with no primary key?
|
|
161
|
+
# Although we have no way to directly reference this record via a show action, we can at least create a link like this:
|
|
162
|
+
# http://localhost:3000/brick/local_authority_postcode?__value=PA2Y+5LQ
|
|
163
|
+
link_to(val, send("#{bt_class.base_class._brick_index(:singular)}_path".to_sym, '__the_id__')).gsub('__the_id__', "?__#{bt[1].first[1]}=#{CGI.escape(val)}")
|
|
164
|
+
else # Normal BT or HOT
|
|
165
|
+
bt_txt = bt_class.brick_descrip(*br_descrip_args)
|
|
166
|
+
bt_txt = ::Brick::Rails.display_binary(bt_txt).html_safe if bt_txt&.encoding&.name == 'ASCII-8BIT'
|
|
167
|
+
bt_txt ||= "<span class=\"orphan\"><< Orphaned ID: #{val} >></span>" if val
|
|
168
|
+
bt_id = bt_class._brick_deserialized_id(obj, bt_id_col)
|
|
169
|
+
(bt_id&.first ? link_to(bt_txt, send("#{bt_class.base_class._brick_index(:singular)}_path".to_sym, bt_id)) : bt_txt || '')
|
|
170
|
+
end
|
|
159
171
|
end
|
|
160
172
|
elsif (hms_col = hms_cols[col_name])
|
|
161
173
|
if hms_col.length == 1
|
|
@@ -165,15 +177,14 @@ module Brick::Rails::FormTags
|
|
|
165
177
|
if col[2] == 'HO'
|
|
166
178
|
descrips = bt_descrip[col_name.to_sym][hm_klass]
|
|
167
179
|
if (descrip_parts = hm_klass._brick_deserialized_value(obj, descrips[0..-2]))&.first
|
|
180
|
+
ho_id = hm_klass._brick_deserialized_id(obj, ho_id_col = descrips.last)
|
|
168
181
|
ho_txt = if hm_klass.name == 'ActiveStorage::Attachment'
|
|
169
182
|
begin
|
|
170
183
|
::Brick::Rails.display_binary(obj.send(col[3])&.blob&.download)&.html_safe
|
|
171
184
|
rescue
|
|
185
|
+
# Attachment is missing for some reason ... default to showing just a description.
|
|
172
186
|
end
|
|
173
|
-
|
|
174
|
-
hm_klass.brick_descrip(obj, descrip_parts, ho_id_col = descrips.last)
|
|
175
|
-
end
|
|
176
|
-
ho_id = hm_klass._brick_deserialized_id(obj, ho_id_col)
|
|
187
|
+
end || hm_klass.brick_descrip(obj, descrip_parts, ho_id_col)
|
|
177
188
|
out << link_to(ho_txt, send("#{hm_klass.base_class._brick_index(:singular)}_path".to_sym, ho_id))
|
|
178
189
|
end
|
|
179
190
|
elsif obj.respond_to?(ct_col = hms_col[1].to_sym) && (ct = obj.send(ct_col)&.to_i)&.positive?
|
|
@@ -402,7 +413,7 @@ module Brick::Rails::FormTags
|
|
|
402
413
|
end
|
|
403
414
|
out << " </tbody>
|
|
404
415
|
</table>
|
|
405
|
-
<script
|
|
416
|
+
<script<%= @_request.env['_brick_nonce'] %>>
|
|
406
417
|
var constellation = document.getElementById(\"#{table_name}\");
|
|
407
418
|
var nextSib,
|
|
408
419
|
_this;
|
|
@@ -868,7 +879,7 @@ function onImagesLoaded(event) {
|
|
|
868
879
|
</select></td>
|
|
869
880
|
<td class=\"paddingTopZero\"><input id=\"txtColName\"></td>
|
|
870
881
|
</tr></table>
|
|
871
|
-
<script
|
|
882
|
+
<script<%= @_request.env['_brick_nonce'] %>>
|
|
872
883
|
var btnAddCol = document.getElementById(\"btnAddCol\");
|
|
873
884
|
btnAddCol.addEventListener(\"click\", function () {
|
|
874
885
|
var txtColName = document.getElementById(\"txtColName\");
|
data/lib/brick/rails.rb
CHANGED
|
@@ -179,7 +179,7 @@ erDiagram
|
|
|
179
179
|
'timestamp without time zone' => 'timestamp',
|
|
180
180
|
'timestamp with time zone' => 'timestamp',
|
|
181
181
|
'time without time zone' => 'time',
|
|
182
|
-
'time with time zone' => 'time' }[dt] || dt&.tr(' (', '_')
|
|
182
|
+
'time with time zone' => 'time' }[dt] || dt&.tr(' (', '_')&.tr(')', '') || 'int'
|
|
183
183
|
end
|
|
184
184
|
callbacks.merge({#{model_short_name.inspect} => ::#{model.name}}).each do |cb_k, cb_class|
|
|
185
185
|
cb_relation = ::Brick.relations[cb_class.table_name]
|
data/lib/brick/reflect_tables.rb
CHANGED
|
@@ -425,8 +425,7 @@ ORDER BY 1, 2, c.internal_column_id, acc.position"
|
|
|
425
425
|
end
|
|
426
426
|
)&.present?
|
|
427
427
|
if tnp.last&.start_with?('::') # TNP that points to an exact class?
|
|
428
|
-
|
|
429
|
-
[singular]
|
|
428
|
+
tnp.last[2..-1].split('::')
|
|
430
429
|
elsif tnp.last
|
|
431
430
|
v[:auto_prefixed_schema], v[:auto_prefixed_class] = tnp
|
|
432
431
|
# v[:resource] = rel_name.last[tnp.first.length..-1]
|
data/lib/brick/version_number.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
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.246
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Lorin Thwaits
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: activerecord
|
|
@@ -246,7 +245,6 @@ homepage: https://github.com/lorint/brick
|
|
|
246
245
|
licenses:
|
|
247
246
|
- MIT
|
|
248
247
|
metadata: {}
|
|
249
|
-
post_install_message:
|
|
250
248
|
rdoc_options: []
|
|
251
249
|
require_paths:
|
|
252
250
|
- lib
|
|
@@ -261,8 +259,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
261
259
|
- !ruby/object:Gem::Version
|
|
262
260
|
version: 1.3.6
|
|
263
261
|
requirements: []
|
|
264
|
-
rubygems_version:
|
|
265
|
-
signing_key:
|
|
262
|
+
rubygems_version: 4.0.18
|
|
266
263
|
specification_version: 4
|
|
267
264
|
summary: Create a Rails app from data alone
|
|
268
265
|
test_files: []
|