brick 1.0.207 → 1.0.209

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 585c18ee97a6ecead8dec67a3bd9ad7ef765524bb109c72c5550f9f0dbd3b98f
4
- data.tar.gz: a0ff5371aef56af539e2022349c0b07c0cdad0bdc93dcbb35aa54a1a8ef3ae4f
3
+ metadata.gz: 9727d5ff3dbf5edcb8ce91b03d0570eec5eb2e0f9ae2c4f456d9d50779321fc9
4
+ data.tar.gz: 32b32f909110d6eca464c775d9725ad049fabf8591daab1088da007ae9a95c5a
5
5
  SHA512:
6
- metadata.gz: 73f5772ef3b440025b50c62b727a58e63392b7642f326d43e63be64f5c2d68eb9fcc1e8a0d77279f0491a284e51cdeb3ca1db90a67bf2b79d1a4f62371575c71
7
- data.tar.gz: 9c068ca26a463307b7f931ca7dcd3c4c12bb06dcc313b284a286aa509ef039b5e4efea1108be9f83839bdb84de47249b9c93a4418dcfc51fe507fd85dba0a6dd
6
+ metadata.gz: 1931290e472f472d93e1536e6517a3865bcc1acd23d15156d48e52c7f35987183b274c8a7c2ac00f09f2f6ac9a4d5663071c84ae4c896de6b4c0069d4a06b1da
7
+ data.tar.gz: 5064ef883fb66feb187fe80a92b3ec700da04feef0f390d720b51497f086bbc1062e505cd467d3624fadb6102bc8dec49b0b6b16a1c04a1a1ceb34e50f4f9ff5
data/lib/brick/config.rb CHANGED
@@ -258,6 +258,18 @@ module Brick
258
258
  @mutex.synchronize { @json_columns = cols }
259
259
  end
260
260
 
261
+ # Restrict all Carrierwave images when set to +true+,
262
+ # or limit to the first n number if set to an Integer
263
+ def limit_carrierwave
264
+ # When not set then by default just do a max of 50 images so that
265
+ # a grid of say 1000 things won't bring the page to its knees
266
+ @mutex.synchronize { @limit_carrierwave ||= 50 }
267
+ end
268
+
269
+ def limit_carrierwave=(num)
270
+ @mutex.synchronize { @limit_carrierwave = num }
271
+ end
272
+
261
273
  def sidescroll
262
274
  @mutex.synchronize { @sidescroll ||= {} }
263
275
  end
@@ -542,25 +542,27 @@ module ActiveRecord
542
542
 
543
543
  # Links from ActiveRecord association pathing names over to the real table
544
544
  # correlation names that get chosen when the AREL AST tree is walked.
545
- def brick_links
545
+ def brick_links(do_dup = true)
546
546
  # Touching AREL AST walks the JoinDependency tree, and in that process uses our
547
547
  # "brick_links" patch to find how every AR chain of association names relates to exact
548
- # table correlation names chosen by AREL. We use a duplicate relation object for this
549
- # because an important side-effect of referencing the AST is that the @arel instance
550
- # variable gets set, and this is a signal to ActiveRecord that a relation has now
551
- # become immutable. (We aren't quite ready for our "real deal" relation object to be
552
- # set in stone ... still need to add .select(), and possibly .where() and .order()
553
- # things ... also if there are any HM counts then an OUTER JOIN for each of them out
554
- # to a derived table to do that counting. All of these things need to know proper
555
- # table correlation names, which will now become available from brick_links on the
556
- # rel_dupe object.)
548
+ # table correlation names chosen by AREL. Unless a relation has already had its AST
549
+ # tree built out, we will use a duplicate relation object for this, because an important
550
+ # side-effect of referencing the AST is that the @arel instance variable gets set. This
551
+ # is a signal to ActiveRecord that a relation has now become immutable. (When Brick is
552
+ # still in the middle of calculating its query, we aren't quite ready for the relation
553
+ # object to be set in stone ... still need to add .select(), and possibly .where() and
554
+ # .order() things ... also if there are any HM counts then an OUTER JOIN for each of
555
+ # them out to a derived table to do that counting. All of these things need to know
556
+ # proper table correlation names, which will now become available from brick_links on
557
+ # the rel_dupe object.)
557
558
  @_brick_links ||= begin
558
559
  # If it's a CollectionProxy (which inherits from Relation) then need to dig
559
560
  # out the core Relation object which is found in the association scope.
560
- rel_dupe = (is_a?(ActiveRecord::Associations::CollectionProxy) ? scope : self).dup
561
+ brick_rel = is_a?(ActiveRecord::Associations::CollectionProxy) ? scope : self
562
+ brick_rel = brick_rel.dup if do_dup
561
563
  # Start out with a hash that has only the root table name
562
- rel_dupe.instance_variable_set(:@_brick_links, bl = { '' => table_name })
563
- rel_dupe.arel.ast # Walk the AST tree in order to capture all the other correlation names
564
+ brick_rel.instance_variable_set(:@_brick_links, bl = { '' => table_name })
565
+ brick_rel.arel.ast if do_dup # Walk the AST tree in order to capture all the other correlation names
564
566
  bl
565
567
  end
566
568
  end
@@ -1,7 +1,8 @@
1
1
  module Brick::Rails::FormBuilder
2
2
  DT_PICKERS = { datetime: 'datetimepicker', timestamp: 'datetimepicker', time: 'timepicker', date: 'datepicker' }
3
3
 
4
- # When this field is one of the appropriate types, will set one of these instance variables accordingly:
4
+ # Render an editable field
5
+ # When it's one of these types, will set an appropriate instance variable truthy accordingly:
5
6
  # @_text_fields_present - To include trix editor
6
7
  # @_date_fields_present - To include flatpickr date / time editor
7
8
  # @_json_fields_present - To include JSONEditor
@@ -37,7 +38,7 @@ module Brick::Rails::FormBuilder
37
38
  "<span class=\"orphan\">Orphaned ID: #{val}</span>".html_safe
38
39
  end
39
40
  out << bt_link if bt_link
40
- elsif @_brick_monetized_attributes&.include?(method)
41
+ elsif model._brick_monetized_attributes&.include?(method)
41
42
  out << self.text_field(method.to_sym, html_options.merge({ value: Money.new(val.to_i).format }))
42
43
  else
43
44
  col_type = if model.json_column?(col) || val.is_a?(Array)
@@ -51,9 +52,9 @@ module Brick::Rails::FormBuilder
51
52
  when :string, :text, :citext,
52
53
  :enum # Support for the activerecord-mysql-enum gem
53
54
  spit_out_text_field = nil
54
- if ::Brick::Rails::FormBuilder.is_bcrypt?(val) # || .readonly?
55
+ if ::Brick::Rails.is_bcrypt?(val) # || .readonly?
55
56
  is_revert = false
56
- out << ::Brick::Rails::FormBuilder.hide_bcrypt(val, nil, 1000)
57
+ out << ::Brick::Rails.hide_bcrypt(val, nil, 1000)
57
58
  elsif col_type == :string
58
59
  if model.respond_to?(:uploaders) && model.uploaders.key?(col.name&.to_sym) &&
59
60
  (url = self.object.send(col.name)&.url) # Carrierwave image?
@@ -139,74 +140,4 @@ module Brick::Rails::FormBuilder
139
140
  "
140
141
  out.html_safe
141
142
  end # brick_field
142
-
143
- # --- CLASS METHODS ---
144
-
145
- def self.is_bcrypt?(val)
146
- val.is_a?(String) && val.length == 60 && val.start_with?('$2a$')
147
- end
148
-
149
- def self.hide_bcrypt(val, is_xml = nil, max_len = 200)
150
- if ::Brick::Rails::FormBuilder.is_bcrypt?(val)
151
- '(hidden)'
152
- else
153
- if val.is_a?(String)
154
- return ::Brick::Rails.display_binary(val) unless (val_utf8 = val.dup.force_encoding('UTF-8')).valid_encoding?
155
-
156
- val = val_utf8.strip
157
- return CGI.escapeHTML(val) if is_xml
158
-
159
- if val.length > max_len
160
- if val[0] == '<' # Seems to be HTML?
161
- cur_len = 0
162
- cur_idx = 0
163
- # Find which HTML tags we might be inside so we can apply ending tags to balance
164
- element_name = nil
165
- in_closing = nil
166
- elements = []
167
- val.each_char do |ch|
168
- case ch
169
- when '<'
170
- element_name = +''
171
- when '/' # First character of tag is '/'?
172
- in_closing = true if element_name == ''
173
- when '>'
174
- if element_name
175
- if in_closing
176
- if (idx = elements.index { |tag| tag.downcase == element_name.downcase })
177
- elements.delete_at(idx)
178
- end
179
- elsif (tag_name = element_name.split.first).present?
180
- elements.unshift(tag_name)
181
- end
182
- element_name = nil
183
- in_closing = nil
184
- end
185
- else
186
- element_name << ch if element_name
187
- end
188
- cur_idx += 1
189
- # Unless it's inside wickets then this is real text content, and see if we're at the limit
190
- break if element_name.nil? && ((cur_len += 1) > max_len)
191
- end
192
- val = val[0..cur_idx]
193
- # Somehow still in the middle of an opening tag right at the end? (Should never happen)
194
- if !in_closing && (tag_name = element_name&.split&.first)&.present?
195
- elements.unshift(tag_name)
196
- val << '>'
197
- end
198
- elements.each do |closing_tag|
199
- val << "</#{closing_tag}>"
200
- end
201
- else # Not HTML, just cut it at the length
202
- val = val[0...max_len]
203
- end
204
- val = "#{val}..."
205
- end
206
- val
207
- else
208
- val.to_s
209
- end
210
- end
211
- end
212
143
  end
@@ -229,11 +229,18 @@ module Brick::Rails::FormTags
229
229
  end
230
230
  end
231
231
  elsif (col = cols[col_name]).is_a?(ActiveRecord::ConnectionAdapters::Column)
232
- # binding.pry if col.is_a?(Array)
233
232
  out << if klass._brick_monetized_attributes&.include?(col_name)
234
233
  val ? Money.new(val.to_i).format : ''
235
234
  elsif klass.respond_to?(:uploaders) && klass.uploaders.key?(col_name.to_sym) &&
236
- (url = obj.send(col_name)&.url) # Carrierwave image?
235
+ (url = obj.send(col.name)&.url) && # Has a Carrierwave URL? ...
236
+ # ... and either not restricting Carrierwave, or under the defined Carrierwave attachment limit?
237
+ (!(limit_carrierwave = ::Brick.config.limit_carrierwave) ||
238
+ (limit_carrierwave.is_a?(Numeric) &&
239
+ (carrierwave_count = instance_variable_get(:@_carrierwave_count) || 0) &&
240
+ ((carrierwave_count += 1) < limit_carrierwave) &&
241
+ instance_variable_set(:@_carrierwave_count, carrierwave_count)
242
+ )
243
+ )
237
244
  "<img class=\"thumbImg\" src=\"#{url}\" title=\"#{val}\">"
238
245
  else
239
246
  lat_lng = if [:float, :decimal].include?(col.type) &&
@@ -663,6 +670,7 @@ btnAddCol.addEventListener(\"click\", function () {
663
670
 
664
671
  private
665
672
 
673
+ # Dig through all instance variables with hopes to find any that appear related to ActiveRecord
666
674
  def _brick_resource_from_iv(trim_ampersand = false)
667
675
  instance_variables.each_with_object(Hash.new { |h, k| h[k] = [] }) do |name, s|
668
676
  iv_name = trim_ampersand ? name.to_s[1..-1] : name
@@ -5,6 +5,9 @@ require 'brick/frameworks/rails/engine'
5
5
 
6
6
  module ::Brick::Rails
7
7
  class << self
8
+ # Low-level way to render read-only data for a field based on its data type.
9
+ # Used by both brick_grid and brick_form_for (which gets down to this low-level
10
+ # implementation from brick_field).
8
11
  def display_value(col_type, val, lat_lng = nil)
9
12
  is_mssql_geography = nil
10
13
  # Some binary thing that really looks like a Microsoft-encoded WGS84 point? (With the first two bytes, E6 10, indicating an EPSG code of 4326)
@@ -68,10 +71,10 @@ module ::Brick::Rails
68
71
  "<a href=\"https://www.google.com/maps/place/#{lat_lng.first}+#{lat_lng.last}/@#{lat_lng.first},#{lat_lng.last},12z\" target=\"blank\">#{val}</a>"
69
72
  elsif val.is_a?(Numeric) && ::ActiveSupport.const_defined?(:NumberHelper)
70
73
  ::ActiveSupport::NumberHelper.number_to_delimited(val, delimiter: ',')
71
- else
72
- ::Brick::Rails::FormBuilder.hide_bcrypt(val, col_type == :xml)
74
+ else # Text or HTML based content
75
+ ::Brick::Rails.hide_bcrypt(val, col_type == :xml)
73
76
  end
74
- else
77
+ else # Don't take chances if we can't figure out the data type
75
78
  '?'
76
79
  end
77
80
  end
@@ -172,7 +175,7 @@ erDiagram
172
175
  def dt_lookup(dt)
173
176
  { 'integer' => 'int', }[dt] || dt&.tr(' ', '_') || 'int'
174
177
  end
175
- callbacks.merge({#{model_short_name} => #{model.name}}).each do |cb_k, cb_class|
178
+ callbacks.merge({#{model_short_name.inspect} => #{model.name}}).each do |cb_k, cb_class|
176
179
  cb_relation = ::Brick.relations[cb_class.table_name]
177
180
  pkeys = cb_relation[:pkey]&.first&.last
178
181
  fkeys = cb_relation[:fks]&.values&.each_with_object([]) { |fk, s| s << fk[:fk] if fk.fetch(:is_bt, nil) }
@@ -201,8 +204,80 @@ erDiagram
201
204
  </div>
202
205
  "
203
206
  end
207
+
208
+ # Render text or HTML without exposing password details
209
+ def hide_bcrypt(val, is_xml = nil, max_len = 200)
210
+ if ::Brick::Rails.is_bcrypt?(val)
211
+ '(hidden)'
212
+ else
213
+ if val.is_a?(String)
214
+ return ::Brick::Rails.display_binary(val) unless (val_utf8 = val.dup.force_encoding('UTF-8')).valid_encoding?
215
+
216
+ val = val_utf8.strip
217
+ return CGI.escapeHTML(val) if is_xml
218
+
219
+ if val.length > max_len
220
+ if val[0] == '<' # Seems to be HTML?
221
+ cur_len = 0
222
+ cur_idx = 0
223
+ # Find which HTML tags we might be inside so we can apply ending tags to balance
224
+ element_name = nil
225
+ in_closing = nil
226
+ elements = []
227
+ val.each_char do |ch|
228
+ case ch
229
+ when '<'
230
+ element_name = +''
231
+ when '/' # First character of tag is '/'?
232
+ in_closing = true if element_name == ''
233
+ when '>'
234
+ if element_name
235
+ if in_closing
236
+ if (idx = elements.index { |tag| tag.downcase == element_name.downcase })
237
+ elements.delete_at(idx)
238
+ end
239
+ elsif (tag_name = element_name.split.first).present?
240
+ elements.unshift(tag_name)
241
+ end
242
+ element_name = nil
243
+ in_closing = nil
244
+ end
245
+ else
246
+ element_name << ch if element_name
247
+ end
248
+ cur_idx += 1
249
+ # Unless it's inside wickets then this is real text content, and see if we're at the limit
250
+ break if element_name.nil? && ((cur_len += 1) > max_len)
251
+ end
252
+ val = val[0..cur_idx]
253
+ # Somehow still in the middle of an opening tag right at the end? (Should never happen)
254
+ if !in_closing && (tag_name = element_name&.split&.first)&.present?
255
+ elements.unshift(tag_name)
256
+ val << '>'
257
+ end
258
+ elements.each do |closing_tag|
259
+ val << "</#{closing_tag}>"
260
+ end
261
+ else # Not HTML, just cut it at the length
262
+ val = val[0...max_len]
263
+ end
264
+ val = "#{val}..."
265
+ end
266
+ val
267
+ else
268
+ val.to_s
269
+ end
270
+ end
271
+ end
272
+
273
+ # Password type data?
274
+ def is_bcrypt?(val)
275
+ val.is_a?(String) && val.length == 60 && val.start_with?('$2a$')
276
+ end
204
277
  end
205
278
 
279
+ # CONSTANTS
280
+
206
281
  AVO_SVG = "<svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 84 90\" height=\"30\" fill=\"#3096F7\">
207
282
  <path d=\"M83.8304 81.0201C83.8343 82.9343 83.2216 84.7996 82.0822 86.3423C80.9427 87.8851 79.3363 89.0244 77.4984 89.5931C75.6606 90.1618 73.6878 90.1302 71.8694 89.5027C70.0509 88.8753 68.4823 87.6851 67.3935 86.1065L67.0796 85.6029C66.9412 85.378 66.8146 85.1463 66.6998 84.9079L66.8821 85.3007C64.1347 81.223 60.419 77.8817 56.0639 75.5723C51.7087 73.263 46.8484 72.057 41.9129 72.0609C31.75 72.0609 22.372 77.6459 16.9336 85.336C17.1412 84.7518 17.7185 83.6137 17.9463 83.0446L19.1059 80.5265L19.1414 80.456C25.2533 68.3694 37.7252 59.9541 52.0555 59.9541C53.1949 59.9541 54.3241 60.0095 55.433 60.1102C60.748 60.6134 65.8887 62.2627 70.4974 64.9433C75.1061 67.6238 79.0719 71.2712 82.1188 75.6314C82.1188 75.6314 82.1441 75.6717 82.1593 75.6868C82.1808 75.717 82.1995 75.749 82.215 75.7825C82.2821 75.8717 82.3446 75.9641 82.4024 76.0595C82.4682 76.1653 82.534 76.4221 82.5999 76.5279C82.6657 76.6336 82.772 76.82 82.848 76.9711L83.1822 77.7063C83.6094 78.7595 83.8294 79.8844 83.8304 81.0201V81.0201Z\" fill=\"currentColor\" fill-opacity=\"0.22\"></path>
208
283
  <path opacity=\"0.25\" d=\"M83.8303 81.015C83.8354 82.9297 83.2235 84.7956 82.0844 86.3393C80.9453 87.8829 79.339 89.0229 77.5008 89.5923C75.6627 90.1617 73.6895 90.1304 71.8706 89.5031C70.0516 88.8758 68.4826 87.6854 67.3935 86.1065L67.0796 85.6029C66.9412 85.3746 66.8146 85.1429 66.6998 84.9079L66.8821 85.3007C64.1353 81.222 60.4199 77.8797 56.0647 75.5695C51.7095 73.2593 46.8488 72.0524 41.9129 72.0558C31.75 72.0558 22.372 77.6408 16.9336 85.3309C17.1412 84.7467 17.7185 83.6086 17.9463 83.0395L19.1059 80.5214L19.1414 80.4509C22.1906 74.357 26.8837 69.2264 32.6961 65.6326C38.5086 62.0387 45.2114 60.1232 52.0555 60.1001C53.1949 60.1001 54.3241 60.1555 55.433 60.2562C60.7479 60.7594 65.8887 62.4087 70.4974 65.0893C75.1061 67.7698 79.0719 71.4172 82.1188 75.7775C82.1188 75.7775 82.1441 75.8177 82.1593 75.8328C82.1808 75.863 82.1995 75.895 82.215 75.9285C82.2821 76.0177 82.3446 76.1101 82.4024 76.2055L82.5999 76.5228C82.6859 76.6638 82.772 76.8149 82.848 76.966L83.1822 77.7012C83.6093 78.7544 83.8294 79.8793 83.8303 81.015Z\" fill=\"currentColor\" fill-opacity=\"0.22\"></path>
@@ -5,7 +5,7 @@ module Brick
5
5
  module VERSION
6
6
  MAJOR = 1
7
7
  MINOR = 0
8
- TINY = 207
8
+ TINY = 209
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
@@ -1512,7 +1512,7 @@ module ActiveRecord
1512
1512
  module QueryMethods
1513
1513
  private
1514
1514
 
1515
- if private_instance_methods.include?(:build_join_query)
1515
+ if private_instance_methods.include?(:build_join_query) # AR 5.0 - 6.0
1516
1516
  alias _brick_build_join_query build_join_query
1517
1517
  def build_join_query(manager, buckets, *args) # , **kwargs)
1518
1518
  # %%% Better way to bring relation into the mix
@@ -1523,7 +1523,7 @@ module ActiveRecord
1523
1523
  _brick_build_join_query(manager, buckets, *args) # , **kwargs)
1524
1524
  end
1525
1525
 
1526
- elsif private_instance_methods.include?(:select_association_list)
1526
+ elsif private_instance_methods.include?(:select_association_list) # AR >= 6.1
1527
1527
  alias _brick_select_association_list select_association_list
1528
1528
  def select_association_list(associations, stashed_joins = nil)
1529
1529
  result = _brick_select_association_list(associations, stashed_joins)
@@ -1531,7 +1531,7 @@ module ActiveRecord
1531
1531
  result
1532
1532
  end
1533
1533
 
1534
- # else # Rails 4.1 ? and older
1534
+ # else # AR 4.2 and older
1535
1535
  # alias _brick_build_joins build_joins
1536
1536
  # def build_joins(manager, joins)
1537
1537
  # result = _brick_build_joins(manager, joins)
@@ -1551,12 +1551,12 @@ module ActiveRecord
1551
1551
  # Capture the table alias name that was chosen
1552
1552
  # if (relation = node.instance_variable_get(:@assocs)&.instance_variable_get(:@relation))
1553
1553
  # link_path = node.instance_variable_get(:@link_path)
1554
- # relation.brick_links[link_path] = result.first.table_alias || result.first.table_name
1554
+ # relation.brick_links(false)[link_path] = result.first.table_alias || result.first.table_name
1555
1555
  # end
1556
1556
  result
1557
1557
  end
1558
1558
  end
1559
- else # For AR >= 4.2
1559
+ else # For AR >= 4.1
1560
1560
  class JoinDependency
1561
1561
  # An intelligent .eager_load() and .includes() that creates t0_r0 style aliases only for the columns
1562
1562
  # used in .select(). To enable this behaviour, include the flag :_brick_eager_load as the first
@@ -1652,7 +1652,7 @@ module ActiveRecord
1652
1652
  # Capture the table alias name that was chosen
1653
1653
  if (relation = node.instance_variable_get(:@assocs)&.instance_variable_get(:@relation))
1654
1654
  link_path = node.instance_variable_get(:@link_path)
1655
- relation.brick_links[link_path] = result.first.table_alias || result.first.table_name
1655
+ relation.brick_links(false)[link_path] = result.first.table_alias || result.first.table_name
1656
1656
  end
1657
1657
  result
1658
1658
  end
@@ -1663,7 +1663,7 @@ module ActiveRecord
1663
1663
  # Capture the table alias name that was chosen
1664
1664
  if (relation = child.instance_variable_get(:@assocs)&.instance_variable_get(:@relation))
1665
1665
  link_path = child.instance_variable_get(:@link_path)
1666
- relation.brick_links[link_path] = if child.table.is_a?(Arel::Nodes::TableAlias)
1666
+ relation.brick_links(false)[link_path] = if child.table.is_a?(Arel::Nodes::TableAlias)
1667
1667
  child.table.right
1668
1668
  else
1669
1669
  # Was: result.first&.left&.table_alias || child.table_name
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.207
4
+ version: 1.0.209
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lorin Thwaits
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-03-17 00:00:00.000000000 Z
11
+ date: 2024-03-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord