brick 1.0.105 → 1.0.106
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/brick/config.rb +5 -6
- data/lib/brick/extensions.rb +69 -49
- data/lib/brick/version_number.rb +1 -1
- data/lib/brick.rb +74 -13
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 988907627ce35c257a41cbcf4b455ec852c9635fe4f8721c5af167e416fbb4ef
|
4
|
+
data.tar.gz: c4a2fe612aa26a628f347d830197f961cf21b67c825ff968fa589e6bd342d1d7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3488a28db2bf8f3c7f363e9b2eb4355e9de2d4021db9a39fb45656f896046bee412a7fd310861f522915bbc244af35a2707005757357ee6b9f9877ea331e7240
|
7
|
+
data.tar.gz: 8a44cbbadde246520b028d0e474226cdf2d43e8d51bed023e20f21a0d5b6cc0e690a397908bcdbdb9b7ef21c7743bec64130258b859d1583b6c0facffd8edf5f
|
data/lib/brick/config.rb
CHANGED
@@ -95,20 +95,19 @@ module Brick
|
|
95
95
|
end
|
96
96
|
|
97
97
|
def api_roots
|
98
|
-
|
99
|
-
@mutex.synchronize { @api_roots || ["/api/#{ver}/"] }
|
98
|
+
@mutex.synchronize { @api_roots || ["/api/v1/"] }
|
100
99
|
end
|
101
100
|
|
102
101
|
def api_roots=(path)
|
103
102
|
@mutex.synchronize { @api_roots = path }
|
104
103
|
end
|
105
104
|
|
106
|
-
def
|
107
|
-
@mutex.synchronize { @
|
105
|
+
def api_filter
|
106
|
+
@mutex.synchronize { @api_filter }
|
108
107
|
end
|
109
108
|
|
110
|
-
def
|
111
|
-
@mutex.synchronize { @
|
109
|
+
def api_filter=(proc)
|
110
|
+
@mutex.synchronize { @api_filter = proc }
|
112
111
|
end
|
113
112
|
|
114
113
|
# Additional table associations to use (Think of these as virtual foreign keys perhaps)
|
data/lib/brick/extensions.rb
CHANGED
@@ -1526,9 +1526,10 @@ class Object
|
|
1526
1526
|
self.protect_from_forgery unless: -> { self.request.format.js? }
|
1527
1527
|
unless is_avo
|
1528
1528
|
self.define_method :index do
|
1529
|
+
request_ver = request.path.split('/')[-2]
|
1529
1530
|
current_api_root = ::Brick.config.api_roots.find do |ar|
|
1530
1531
|
request.path.start_with?(ar) || # Exact match?
|
1531
|
-
|
1532
|
+
request_ver == ar.split('/').last # Version at least matches?
|
1532
1533
|
end
|
1533
1534
|
if (current_api_root || is_openapi) &&
|
1534
1535
|
!params&.key?('_brick_schema') &&
|
@@ -1542,51 +1543,63 @@ class Object
|
|
1542
1543
|
_schema, @_is_show_schema_list = ::Brick.set_db_schema(params || api_params)
|
1543
1544
|
|
1544
1545
|
if is_openapi
|
1546
|
+
api_name = Rswag::Ui.config.config_object[:urls].find do |api_url|
|
1547
|
+
api_url[:url] == request.path
|
1548
|
+
end&.fetch(:name, 'API documentation')
|
1545
1549
|
current_api_ver = current_api_root.split('/').last&.[](1..-1).to_i
|
1546
|
-
json = { 'openapi': '3.0.1', 'info': { 'title':
|
1550
|
+
json = { 'openapi': '3.0.1', 'info': { 'title': api_name, 'version': request_ver },
|
1547
1551
|
'servers': [
|
1548
|
-
{ 'url': '{scheme}://{defaultHost}',
|
1549
|
-
'
|
1550
|
-
|
1551
|
-
|
1552
|
+
{ 'url': '{scheme}://{defaultHost}',
|
1553
|
+
'variables': {
|
1554
|
+
'scheme': { 'default': request.env['rack.url_scheme'] },
|
1555
|
+
'defaultHost': { 'default': request.env['HTTP_HOST'] }
|
1556
|
+
}
|
1557
|
+
}
|
1552
1558
|
]
|
1553
1559
|
}
|
1554
|
-
|
1555
|
-
|
1560
|
+
unless ::Brick.config.enable_api == false
|
1561
|
+
json['paths'] = relations.each_with_object({}) do |relation, s|
|
1556
1562
|
next if (api_vers = relation.last.fetch(:api, nil)) &&
|
1557
|
-
!(
|
1558
|
-
|
1559
|
-
|
1560
|
-
|
1561
|
-
|
1562
|
-
|
1563
|
-
|
1564
|
-
|
1565
|
-
|
1566
|
-
|
1567
|
-
|
1568
|
-
|
1569
|
-
|
1570
|
-
|
1571
|
-
|
1572
|
-
|
1573
|
-
|
1574
|
-
|
1575
|
-
|
1576
|
-
|
1577
|
-
|
1578
|
-
|
1579
|
-
|
1580
|
-
|
1581
|
-
|
1582
|
-
|
1583
|
-
|
1584
|
-
|
1585
|
-
|
1586
|
-
|
1587
|
-
|
1588
|
-
|
1589
|
-
|
1563
|
+
!(api_ver_paths = api_vers[current_api_ver])
|
1564
|
+
|
1565
|
+
# binding.pry if relation.last.fetch(:isView, nil) && api_ver_paths != { relation.first => ::Brick::ALL_API_ACTIONS }
|
1566
|
+
(api_ver_paths || { relation.first => ::Brick::ALL_API_ACTIONS }).each do |api_ver_path, actions|
|
1567
|
+
relation_name = api_ver_path || relation.first.tr('.', '/')
|
1568
|
+
table_description = relation.last[:description]
|
1569
|
+
unless actions&.exclude?(:index)
|
1570
|
+
s["#{current_api_root}#{relation_name}"] = {
|
1571
|
+
'get': {
|
1572
|
+
'summary': "list #{relation.first}",
|
1573
|
+
'description': table_description,
|
1574
|
+
'parameters': relation.last[:cols].map do |k, v|
|
1575
|
+
param = { in: 'query', 'name' => k, 'schema': { 'type': v.first } }
|
1576
|
+
if (col_descrip = relation.last.fetch(:col_descrips, nil)&.fetch(k, nil))
|
1577
|
+
param['description'] = col_descrip
|
1578
|
+
end
|
1579
|
+
param
|
1580
|
+
end,
|
1581
|
+
'responses': { '200': { 'description': 'successful' } }
|
1582
|
+
}
|
1583
|
+
}
|
1584
|
+
end
|
1585
|
+
|
1586
|
+
unless actions&.exclude?(:update)
|
1587
|
+
s["#{current_api_root}#{relation_name}/{id}"] = {
|
1588
|
+
'patch': {
|
1589
|
+
'summary': "update a #{relation.first.singularize}",
|
1590
|
+
'description': table_description,
|
1591
|
+
'parameters': relation.last[:cols].reject { |k, v| Brick.config.metadata_columns.include?(k) }.map do |k, v|
|
1592
|
+
param = { 'name' => k, 'schema': { 'type': v.first } }
|
1593
|
+
if (col_descrip = relation.last.fetch(:col_descrips, nil)&.fetch(k, nil))
|
1594
|
+
param['description'] = col_descrip
|
1595
|
+
end
|
1596
|
+
param
|
1597
|
+
end,
|
1598
|
+
'responses': { '200': { 'description': 'successful' } }
|
1599
|
+
}
|
1600
|
+
} unless relation.last.fetch(:isView, nil)
|
1601
|
+
end
|
1602
|
+
end # Do multiple api_ver_paths
|
1590
1603
|
end
|
1591
1604
|
end
|
1592
1605
|
render inline: json.to_json, content_type: request.format
|
@@ -1600,11 +1613,11 @@ class Object
|
|
1600
1613
|
end
|
1601
1614
|
render inline: exported_csv, content_type: request.format
|
1602
1615
|
return
|
1603
|
-
elsif request.format == :js || current_api_root # Asking for JSON?
|
1604
|
-
|
1605
|
-
|
1606
|
-
|
1607
|
-
|
1616
|
+
# elsif request.format == :js || current_api_root # Asking for JSON?
|
1617
|
+
# # %%% Add: where, order, page, page_size, offset, limit
|
1618
|
+
# data = (model.is_view? || !Object.const_defined?('DutyFree')) ? model.limit(1000) : model.df_export(model.brick_import_template)
|
1619
|
+
# render inline: { data: data }.to_json, content_type: request.format == '*/*' ? 'application/json' : request.format
|
1620
|
+
# return
|
1608
1621
|
end
|
1609
1622
|
|
1610
1623
|
# Normal (not swagger or CSV) request
|
@@ -1616,8 +1629,15 @@ class Object
|
|
1616
1629
|
|
1617
1630
|
ar_relation = ActiveRecord.version < Gem::Version.new('4') ? model.preload : model.all
|
1618
1631
|
@_brick_params = ar_relation.brick_select(params, (selects ||= []), order_by,
|
1619
|
-
|
1620
|
-
|
1632
|
+
translations = {},
|
1633
|
+
join_array = ::Brick::JoinArray.new)
|
1634
|
+
|
1635
|
+
if request.format == :js || current_api_root # Asking for JSON?
|
1636
|
+
data = ar_relation.respond_to?(:_select!) ? ar_relation.dup._select!(*selects) : ar_relation.select(selects)
|
1637
|
+
render inline: { data: data }.to_json, content_type: request.format == '*/*' ? 'application/json' : request.format
|
1638
|
+
return
|
1639
|
+
end
|
1640
|
+
|
1621
1641
|
# %%% Add custom HM count columns
|
1622
1642
|
# %%% What happens when the PK is composite?
|
1623
1643
|
counts = model._br_hm_counts.each_with_object([]) do |v, s|
|
@@ -2127,7 +2147,7 @@ ORDER BY 1, 2, c.internal_column_id, acc.position"
|
|
2127
2147
|
# AND kcu2.TABLE_NAME = ?;", Apartment::Tenant.current, table_name
|
2128
2148
|
fk_references = ActiveRecord::Base.execute_sql(sql)
|
2129
2149
|
when 'SQLite'
|
2130
|
-
sql = "SELECT m.name, fkl.\"from\", fkl.\"table\", m.name || '_' || fkl.\"from\" AS constraint_name
|
2150
|
+
sql = "SELECT NULL AS constraint_schema, m.name, fkl.\"from\", NULL AS primary_schema, fkl.\"table\", m.name || '_' || fkl.\"from\" AS constraint_name
|
2131
2151
|
FROM sqlite_master m
|
2132
2152
|
INNER JOIN pragma_foreign_key_list(m.name) fkl ON m.type = 'table'
|
2133
2153
|
ORDER BY m.name, fkl.seq"
|
data/lib/brick/version_number.rb
CHANGED
data/lib/brick.rb
CHANGED
@@ -124,6 +124,8 @@ if Gem::Specification.all_names.any? { |g| g.start_with?('rails-') }
|
|
124
124
|
require 'brick/frameworks/rails'
|
125
125
|
end
|
126
126
|
module Brick
|
127
|
+
ALL_API_ACTIONS = [:index, :show, :create, :update, :destroy]
|
128
|
+
|
127
129
|
class << self
|
128
130
|
def sti_models
|
129
131
|
@sti_models ||= {}
|
@@ -347,6 +349,16 @@ module Brick
|
|
347
349
|
Brick.config.api_roots
|
348
350
|
end
|
349
351
|
|
352
|
+
# @api public
|
353
|
+
def api_filter=(proc)
|
354
|
+
Brick.config.api_filter = proc
|
355
|
+
end
|
356
|
+
|
357
|
+
# @api public
|
358
|
+
def api_filter
|
359
|
+
Brick.config.api_filter
|
360
|
+
end
|
361
|
+
|
350
362
|
# @api public
|
351
363
|
def skip_database_views=(value)
|
352
364
|
Brick.config.skip_database_views = value
|
@@ -675,6 +687,7 @@ In config/initializers/brick.rb appropriate entries would look something like:
|
|
675
687
|
api_done_views = (versioned_views[api_root] ||= {})
|
676
688
|
found = nil
|
677
689
|
view_relation = nil
|
690
|
+
actions = ::Brick::ALL_API_ACTIONS # By default all actions are allowed
|
678
691
|
# If it's a view then see if there's a versioned one available by searching for resource names
|
679
692
|
# versioned with the closest number (equal to or less than) compared with our API version number.
|
680
693
|
if v.key?(:isView) && (ver = k.match(/^v([\d_]*)/).captures.first)[-1] == '_'
|
@@ -687,15 +700,15 @@ In config/initializers/brick.rb appropriate entries would look something like:
|
|
687
700
|
api_ver = api_root.split('/')[-1]&.gsub('_', '.')
|
688
701
|
vn_idx = api_ver.rindex(/[^\d._]/) # Position of the first numeric digit at the end of the version number
|
689
702
|
# Was: .to_d
|
690
|
-
api_ver_num = api_ver[vn_idx + 1..-1].gsub('_', '.').to_i # Attempt to turn something like "v3" into the decimal value 3
|
703
|
+
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
|
691
704
|
# puts [api_ver, vn_idx, api_ver_num, unversioned].inspect
|
692
705
|
|
693
706
|
next if ver.to_i > api_ver_num # Don't surface any newer views in an older API
|
694
707
|
|
695
|
-
|
696
|
-
|
697
|
-
found = "v#{
|
698
|
-
|
708
|
+
test_ver_num -= 1 until test_ver_num.zero? ||
|
709
|
+
(view_relation = ::Brick.relations.fetch(
|
710
|
+
found = "v#{test_ver_num}_#{k[ver.length + 1..-1]}", nil
|
711
|
+
))
|
699
712
|
api_done_views[unversioned] = nil # Mark that for this API version this view is done
|
700
713
|
|
701
714
|
# puts "Found #{found}" if view_relation
|
@@ -705,21 +718,69 @@ In config/initializers/brick.rb appropriate entries would look something like:
|
|
705
718
|
view_relation ||= ::Brick.relations.fetch(found = unversioned,
|
706
719
|
::Brick.relations.fetch(found = unversioned, nil)
|
707
720
|
)
|
708
|
-
if found && view_relation && k !=
|
709
|
-
|
721
|
+
if found && view_relation && k != unversioned
|
722
|
+
# Call proc that limits which endpoints get surfaced based on version, table or view name, method (get list / get one / post / patch / delete)
|
723
|
+
# Returning nil makes it do nothing, false makes it skip creating this endpoint, and an array of up to
|
724
|
+
# these 3 things controls and changes the nature of the endpoint that gets built:
|
725
|
+
# (updated api_name, name of different relation to route to, allowed actions such as :index, :show, :create, etc)
|
726
|
+
proc_result = if (filter = ::Brick.config.api_filter).is_a?(Proc)
|
727
|
+
begin
|
728
|
+
filter.call(unversioned, k, actions, api_ver_num, found, test_ver_num)
|
729
|
+
rescue StandardError => e
|
730
|
+
puts "::Brick.api_filter Proc error: #{e.message}"
|
731
|
+
end
|
732
|
+
end
|
733
|
+
# proc_result expects to receive back: [updated_api_name, to_other_relation, allowed_actions]
|
734
|
+
|
735
|
+
case proc_result
|
736
|
+
when NilClass
|
737
|
+
# Do nothing differently than what normal behaviour would be
|
738
|
+
when FalseClass # Skip implementing this endpoint
|
739
|
+
view_relation[:api][api_ver_num] = nil
|
740
|
+
next
|
741
|
+
when Array # Did they give back an array of actions?
|
742
|
+
unless proc_result.any? { |pr| ::Brick::ALL_API_ACTIONS.exclude?(pr) }
|
743
|
+
proc_result = [unversioned, to_relation, proc_result]
|
744
|
+
end
|
745
|
+
# Otherwise don't change this array because it's probably legit
|
746
|
+
when String
|
747
|
+
proc_result = [proc_result] # Treat this as the surfaced api_name (path) they want to use for this endpoint
|
748
|
+
else
|
749
|
+
puts "::Brick.api_filter Proc warning: Unable to parse this result returned: \n #{proc_result.inspect}"
|
750
|
+
proc_result = nil # Couldn't understand what in the world was returned
|
751
|
+
end
|
752
|
+
|
753
|
+
if proc_result&.present?
|
754
|
+
if proc_result[1] # to_other_relation
|
755
|
+
if (new_view_relation = ::Brick.relations.fetch(proc_result[1], nil))
|
756
|
+
k = proc_result[1] # Route this call over to this different relation
|
757
|
+
view_relation = new_view_relation
|
758
|
+
else
|
759
|
+
puts "::Brick.api_filter Proc warning: Unable to find new suggested relation with name #{proc_result[1]} -- sticking with #{k} instead."
|
760
|
+
end
|
761
|
+
end
|
762
|
+
if proc_result.first&.!=(k) # updated_api_name -- a different name than this relation would normally have
|
763
|
+
found = proc_result.first
|
764
|
+
end
|
765
|
+
actions &= proc_result[2] if proc_result[2] # allowed_actions
|
766
|
+
end
|
710
767
|
end
|
768
|
+
(view_relation[:api][api_ver_num] ||= {})[found] = actions # Add to the list of API paths this resource responds to
|
711
769
|
end
|
712
770
|
|
713
771
|
# view_ver_num = if (first_part = k.split('_').first) =~ /^v[\d_]+/
|
714
772
|
# first_part[1..-1].gsub('_', '.').to_i
|
715
773
|
# end
|
716
774
|
controller_name = view_relation.fetch(:resource, nil)&.pluralize if view_relation
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
775
|
+
# %%% So far we can only surface the #index action
|
776
|
+
if actions.include?(:index)
|
777
|
+
if schema_name
|
778
|
+
full_resource = "#{schema_name}/#{found || v[:resource]}"
|
779
|
+
send(:get, "#{api_root}#{full_resource}", { to: "#{controller_prefix}#{schema_name}/#{controller_name}#index" })
|
780
|
+
else
|
781
|
+
# Normally goes to something like: /api/v1/employees
|
782
|
+
send(:get, "#{api_root}#{found || v[:resource]}", { to: "#{controller_prefix}#{controller_name}#index" })
|
783
|
+
end
|
723
784
|
end
|
724
785
|
end
|
725
786
|
|
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.106
|
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-01-
|
11
|
+
date: 2023-01-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -164,6 +164,20 @@ dependencies:
|
|
164
164
|
- - "~>"
|
165
165
|
- !ruby/object:Gem::Version
|
166
166
|
version: 1.42.0
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: rswag-ui
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '0'
|
167
181
|
- !ruby/object:Gem::Dependency
|
168
182
|
name: mysql2
|
169
183
|
requirement: !ruby/object:Gem::Requirement
|