bp3-core 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +43 -0
- data/.ruby-version +2 -0
- data/.yardopts +8 -0
- data/CHANGELOG.md +13 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +120 -0
- data/LICENSE.txt +21 -0
- data/README.md +82 -0
- data/Rakefile +12 -0
- data/bp3-core.gemspec +46 -0
- data/lib/bp3/core/actions.rb +208 -0
- data/lib/bp3/core/cookies.rb +139 -0
- data/lib/bp3/core/displayable.rb +77 -0
- data/lib/bp3/core/feature_flags.rb +42 -0
- data/lib/bp3/core/ransackable.rb +51 -0
- data/lib/bp3/core/rqid.rb +40 -0
- data/lib/bp3/core/settings.rb +17 -0
- data/lib/bp3/core/sqnr.rb +20 -0
- data/lib/bp3/core/tenantable.rb +143 -0
- data/lib/bp3/core/test.rb +48 -0
- data/lib/bp3/core/version.rb +7 -0
- data/lib/bp3/core.rb +20 -0
- data/lib/bp3-core.rb +3 -0
- data/sig/bp3/core.rbs +6 -0
- metadata +183 -0
@@ -0,0 +1,139 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bp3
|
4
|
+
module Core
|
5
|
+
module Cookies
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
attr_reader :current_visitor
|
10
|
+
|
11
|
+
before_action :check_visitor_cookie
|
12
|
+
end
|
13
|
+
|
14
|
+
VISITOR_COOKIE_NAME_PREFIX = '_bp3_visitor'
|
15
|
+
DO_NOT_TRACK_VALUE = 'do_not_track'
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def do_not_track
|
20
|
+
return @do_not_track unless @do_not_track.nil? # could be set to true or false already
|
21
|
+
|
22
|
+
cookie_value = cookies[new_visitor_cookie_name]
|
23
|
+
@do_not_track = cookie_value == DO_NOT_TRACK_VALUE
|
24
|
+
reset_session if @do_not_track
|
25
|
+
@do_not_track
|
26
|
+
end
|
27
|
+
|
28
|
+
def set_do_not_track
|
29
|
+
# this replaces the signed temporary cookie with an unsigned, permanent cookie
|
30
|
+
cookies.permanent[new_visitor_cookie_name] = DO_NOT_TRACK_VALUE
|
31
|
+
end
|
32
|
+
|
33
|
+
def start_tracking
|
34
|
+
return unless do_not_track
|
35
|
+
|
36
|
+
cookies.delete(visitor_cookie_name)
|
37
|
+
@do_not_track = false
|
38
|
+
check_visitor_cookie
|
39
|
+
end
|
40
|
+
|
41
|
+
def check_visitor_cookie
|
42
|
+
switch_old_to_new
|
43
|
+
check_new_visitor_cookie
|
44
|
+
end
|
45
|
+
|
46
|
+
def switch_old_to_new
|
47
|
+
cookie_value = cookies.signed[visitor_cookie_name]
|
48
|
+
return if cookie_value.blank?
|
49
|
+
|
50
|
+
_sites_site_id, _tenant_id, identification = cookie_value&.split('/')
|
51
|
+
|
52
|
+
message = "check_visitor_cookie: switching to new visitor_cookie for #{identification}"
|
53
|
+
Rails.logger.debug message
|
54
|
+
cookies.delete(visitor_cookie_name)
|
55
|
+
cookies.signed[new_visitor_cookie_name] = {
|
56
|
+
value: identification,
|
57
|
+
expires: 365.days.from_now
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
62
|
+
def check_old_visitor_cookie
|
63
|
+
cookie_value = cookies.signed[visitor_cookie_name]
|
64
|
+
return if cookie_value.blank? && do_not_track
|
65
|
+
|
66
|
+
sites_site_id, tenant_id, identification = cookie_value&.split('/')
|
67
|
+
if sites_site_id && sites_site_id != GRS.current_site.id
|
68
|
+
Rails.logger.warn { "check_visitor_cookie: site mismatch! (#{sites_site_id} and #{GRS.current_site.id}" }
|
69
|
+
end
|
70
|
+
if tenant_id && tenant_id != GRS.current_tenant.id
|
71
|
+
Rails.logger.warn { "check_visitor_cookie: tenant mismatch! (#{tenant_id} and #{GRS.current_tenant.id}" }
|
72
|
+
end
|
73
|
+
visitor = Users::Visitor.find_by(sites_site_id:, tenant_id:, identification:)
|
74
|
+
if visitor.nil?
|
75
|
+
visitor = create_visitor
|
76
|
+
message = "check_visitor_cookie: create_visitor #{visitor.id} and create #{visitor_cookie_name} cookie"
|
77
|
+
Rails.logger.debug message
|
78
|
+
cookies.signed[visitor_cookie_name] = {
|
79
|
+
value: visitor.scoped_identification,
|
80
|
+
expires: 365.days.from_now
|
81
|
+
}
|
82
|
+
end
|
83
|
+
@current_visitor = GlobalRequestState.current_visitor = visitor
|
84
|
+
Rails.logger.debug do
|
85
|
+
"check_visitor_cookie: cookie[#{visitor_cookie_name}]=#{cookies.signed[visitor_cookie_name]}"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
89
|
+
|
90
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
91
|
+
def check_new_visitor_cookie
|
92
|
+
cookie_value = cookies.signed[new_visitor_cookie_name]
|
93
|
+
return if cookie_value.blank? && do_not_track
|
94
|
+
|
95
|
+
identification = cookie_value
|
96
|
+
sites_site_id = GRS.current_site_id
|
97
|
+
tenant_id = GRS.current_tenant_id
|
98
|
+
visitor = Users::Visitor.find_by(sites_site_id:, tenant_id:, identification:)
|
99
|
+
if visitor.nil?
|
100
|
+
visitor = create_visitor
|
101
|
+
message = "check_visitor_cookie: create_visitor #{visitor.id} and create #{new_visitor_cookie_name} cookie"
|
102
|
+
Rails.logger.debug message
|
103
|
+
cookies.signed[new_visitor_cookie_name] = {
|
104
|
+
value: visitor.identification,
|
105
|
+
expires: 365.days.from_now
|
106
|
+
}
|
107
|
+
end
|
108
|
+
@current_visitor = GlobalRequestState.current_visitor = visitor
|
109
|
+
Rails.logger.debug do
|
110
|
+
"check_visitor_cookie: cookie[#{new_visitor_cookie_name}]=#{cookies.signed[new_visitor_cookie_name]}"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
114
|
+
|
115
|
+
def visitor_cookie_name
|
116
|
+
@visitor_cookie_name ||= "#{VISITOR_COOKIE_NAME_PREFIX}_#{cookie_site_id}_#{cookie_tenant_id}"
|
117
|
+
end
|
118
|
+
|
119
|
+
def new_visitor_cookie_name
|
120
|
+
VISITOR_COOKIE_NAME_PREFIX
|
121
|
+
end
|
122
|
+
|
123
|
+
def create_visitor
|
124
|
+
Users::Visitor.create!(sites_site: GRS.current_site,
|
125
|
+
tenant: GRS.current_tenant,
|
126
|
+
workspaces_workspace: GRS.current_workspace,
|
127
|
+
identification: SecureRandom.uuid)
|
128
|
+
end
|
129
|
+
|
130
|
+
def cookie_site_id
|
131
|
+
GRS.current_site.id[0..7]
|
132
|
+
end
|
133
|
+
|
134
|
+
def cookie_tenant_id
|
135
|
+
GRS.current_tenant.id[0..7]
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'action_view/record_identifier'
|
4
|
+
require 'active_support/parameter_filter'
|
5
|
+
|
6
|
+
module Bp3
|
7
|
+
module Core
|
8
|
+
module Displayable
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
def to_dom_id
|
12
|
+
ActionView::RecordIdentifier.dom_id(self)
|
13
|
+
end
|
14
|
+
|
15
|
+
def display_name
|
16
|
+
admin_display_name
|
17
|
+
end
|
18
|
+
|
19
|
+
def admin_display_name
|
20
|
+
"#{self.class.name.split('::').last} #{id}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def filtered_attributes
|
24
|
+
filter_object_fields if respond_to?(:object)
|
25
|
+
filter_attributes
|
26
|
+
end
|
27
|
+
|
28
|
+
def i18n_key
|
29
|
+
self.class.i18n_key
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def version_filter_mask
|
35
|
+
'[FILTERED][DC]'
|
36
|
+
end
|
37
|
+
|
38
|
+
def filter_attributes
|
39
|
+
filter.filter(attributes)
|
40
|
+
end
|
41
|
+
|
42
|
+
def filter_object_fields
|
43
|
+
self.object = filter.filter(object) if object.present?
|
44
|
+
return if object_changes.blank?
|
45
|
+
|
46
|
+
filtered_object_changes = filter.filter(object_changes)
|
47
|
+
filtered_object_changes.each_key do |key|
|
48
|
+
if filtered_object_changes[key] == version_filter_mask
|
49
|
+
filtered_object_changes[key] =
|
50
|
+
mark_changes_as_filtered(key)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
self.object_changes = filtered_object_changes
|
54
|
+
end
|
55
|
+
|
56
|
+
def filter
|
57
|
+
return @filter if @filter
|
58
|
+
|
59
|
+
filters = Rails.application.config.filter_parameters
|
60
|
+
@filter = ActiveSupport::ParameterFilter.new(filters, mask: version_filter_mask)
|
61
|
+
end
|
62
|
+
|
63
|
+
def mark_changes_as_filtered(key)
|
64
|
+
change = object_changes[key]
|
65
|
+
change[0] = version_filter_mask if change[0].present?
|
66
|
+
change[1] = version_filter_mask if change[1].present?
|
67
|
+
change
|
68
|
+
end
|
69
|
+
|
70
|
+
class_methods do
|
71
|
+
def i18n_key
|
72
|
+
name.downcase.gsub('::', '/')
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bp3
|
4
|
+
module Core
|
5
|
+
module FeatureFlags
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
def efcfon?(flag, ref: nil, default: nil)
|
9
|
+
ef = efon(flag, ref:, default: nil)
|
10
|
+
cf = cfon(flag, ref:, default: nil)
|
11
|
+
|
12
|
+
if ef.nil? && cf.nil?
|
13
|
+
default || false
|
14
|
+
elsif ef.nil?
|
15
|
+
cf
|
16
|
+
elsif cf.nil?
|
17
|
+
ef
|
18
|
+
else
|
19
|
+
cf || ef
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def efon(flag, ref: nil, default: nil)
|
24
|
+
Feature::Enabler.on(flag, enablable: ref, default:)
|
25
|
+
end
|
26
|
+
|
27
|
+
def efon?(flag, ref: nil, default: nil)
|
28
|
+
efon(flag, ref:, default:) || default || false
|
29
|
+
end
|
30
|
+
|
31
|
+
def cfon(flag, ref: nil, default: nil)
|
32
|
+
return default if ref.nil?
|
33
|
+
|
34
|
+
ref.configs&.[](flag)
|
35
|
+
end
|
36
|
+
|
37
|
+
def cfon?(flag, ref: nil, default: nil)
|
38
|
+
cfon(flag, ref:, default:) || default || false
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bp3
|
4
|
+
# Bp3::Ransackable provides class methods expected by models that use ransack
|
5
|
+
module Core
|
6
|
+
module Ransackable
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
mattr_accessor :attribute_exceptions, default: []
|
10
|
+
mattr_accessor :association_exceptions, default: []
|
11
|
+
|
12
|
+
class_methods do
|
13
|
+
def ransackable_fields(auth_object = nil)
|
14
|
+
fields =
|
15
|
+
ransackable_attributes(auth_object) +
|
16
|
+
ransackable_associations(auth_object) +
|
17
|
+
ransackable_scopes(auth_object)
|
18
|
+
fields.map(&:to_sym).uniq
|
19
|
+
end
|
20
|
+
|
21
|
+
def ransackable_attributes(_auth_object = nil)
|
22
|
+
except = attribute_exceptions.map(&:to_s)
|
23
|
+
column_names.map(&:to_s) - except
|
24
|
+
end
|
25
|
+
|
26
|
+
def ransackable_associations(_auth_object = nil)
|
27
|
+
except = association_exceptions.map(&:to_s)
|
28
|
+
reflect_on_all_associations.map(&:name).map(&:to_s) - except
|
29
|
+
end
|
30
|
+
|
31
|
+
def ransackable_scopes(_auth_object = nil)
|
32
|
+
[]
|
33
|
+
end
|
34
|
+
|
35
|
+
def ransortable_attributes(auth_object = nil)
|
36
|
+
ransackable_attributes(auth_object)
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def attribute_exceptions
|
42
|
+
Bp3::Core::Ransackable.attribute_exceptions
|
43
|
+
end
|
44
|
+
|
45
|
+
def association_exceptions
|
46
|
+
Bp3::Core::Ransackable.association_exceptions
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bp3
|
4
|
+
module Core
|
5
|
+
module Rqid
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
mattr_accessor :global_request_state_class_name, :global_request_state_method
|
9
|
+
|
10
|
+
def self.global_request_state_class
|
11
|
+
@@global_request_state_class ||= global_request_state_class_name.constantize # rubocop:disable Style/ClassVars
|
12
|
+
end
|
13
|
+
|
14
|
+
included do
|
15
|
+
before_create :set_rqid
|
16
|
+
|
17
|
+
# CAUTION: these are defined as belongs_to, therefore returning one record. However, it is possible
|
18
|
+
# that multiple such records exist
|
19
|
+
belongs_to :original_request, class_name: 'Inbound::Request',
|
20
|
+
foreign_key: :rqid, primary_key: :rqid, optional: true
|
21
|
+
belongs_to :original_response, class_name: 'Inbound::Response',
|
22
|
+
foreign_key: :rqid, primary_key: :rqid, optional: true
|
23
|
+
belongs_to :original_visit, class_name: 'Visit',
|
24
|
+
foreign_key: :rqid, primary_key: :rqid, optional: true
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def set_rqid
|
30
|
+
return if rqid
|
31
|
+
|
32
|
+
self.rqid = rqid_from_global_state
|
33
|
+
end
|
34
|
+
|
35
|
+
def rqid_from_global_state
|
36
|
+
Bp3::Core::Rqid.global_request_state_class.send(Bp3::Core::Rqid.global_request_state_method)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bp3
|
4
|
+
module Core
|
5
|
+
module Settings
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
def create_request_record_is_on?
|
9
|
+
efcfon?(:create_request_record, ref: current_site, default: true)
|
10
|
+
end
|
11
|
+
|
12
|
+
def multi_tenant_is_on?
|
13
|
+
efcfon?('multi-tenant', ref: current_site, default: false)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bp3
|
4
|
+
module Core
|
5
|
+
module Sqnr
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
scope :sqnr, -> { order(sqnr: :asc) }
|
10
|
+
scope :rnqs, -> { order(sqnr: :desc) }
|
11
|
+
end
|
12
|
+
|
13
|
+
class_methods do
|
14
|
+
def use_sqnr_for_ordering
|
15
|
+
self.implicit_order_column = :sqnr
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bp3
|
4
|
+
module Core
|
5
|
+
module Tenantable
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
# call connection to make sure the db meta data has been loaded
|
10
|
+
ignore_notifications_string = (ENV['IGNORE_NOTIFICATIONS'] || '').strip
|
11
|
+
connection if ignore_notifications_string.empty?
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def set_sites_site_id
|
17
|
+
return if sites_site_id || sites_site
|
18
|
+
|
19
|
+
self.sites_site_id = GlobalRequestState.either_site_id
|
20
|
+
end
|
21
|
+
|
22
|
+
def set_tenant_id
|
23
|
+
return if tenant_id || tenant
|
24
|
+
|
25
|
+
self.tenant_id = GlobalRequestState.either_tenant_id
|
26
|
+
end
|
27
|
+
|
28
|
+
def tenant_matches_site
|
29
|
+
tid = tenant_id || tenant&.id
|
30
|
+
return if tid.nil?
|
31
|
+
|
32
|
+
tenant ||= Tenant.find(tid)
|
33
|
+
return if (sites_site_id || sites_site&.id) == tenant.sites_site_id
|
34
|
+
|
35
|
+
errors.add(:tenant, :must_match_site)
|
36
|
+
end
|
37
|
+
|
38
|
+
def set_workspaces_workspace_id
|
39
|
+
return if workspaces_workspace_id || workspaces_workspace
|
40
|
+
|
41
|
+
self.workspaces_workspace_id = GlobalRequestState.either_workspace_id
|
42
|
+
end
|
43
|
+
|
44
|
+
def workspaces_workspace_matches_site
|
45
|
+
wid = workspaces_workspace_id || workspaces_workspace&.id
|
46
|
+
return if wid.nil?
|
47
|
+
|
48
|
+
workspaces_workspace ||= Workspaces::Workspace.find(wid)
|
49
|
+
return if (sites_site_id || sites_site&.id) == workspaces_workspace.sites_site_id
|
50
|
+
|
51
|
+
errors.add(:workspaces_workspace, :must_match_site)
|
52
|
+
end
|
53
|
+
|
54
|
+
# rubocop:disable: Metrics/BlockLength
|
55
|
+
class_methods do
|
56
|
+
def configure_tenancy(tenancy_configuration = {})
|
57
|
+
@tenancy_configuration = default_configuration.merge(tenancy_configuration)
|
58
|
+
may_belong_to_site
|
59
|
+
may_belong_to_tenant
|
60
|
+
may_belong_to_workspace
|
61
|
+
rescue ActiveRecord::StatementInvalid, PG::UndefinedTable => e
|
62
|
+
Rails.logger.error { "ERROR in configure_tenancy: #{e.message}" }
|
63
|
+
# log_exception(e) # infinite loop
|
64
|
+
end
|
65
|
+
|
66
|
+
def may_belong_to_site
|
67
|
+
column = columns.detect { |c| c.name == 'sites_site_id' }
|
68
|
+
return if column.nil?
|
69
|
+
|
70
|
+
@tenancy_configuration[:belongs_to_site] = true
|
71
|
+
optional = column.null
|
72
|
+
belongs_to(:sites_site, class_name: 'Sites::Site', optional:)
|
73
|
+
alias_method :site, :sites_site
|
74
|
+
alias_method :site=, :sites_site=
|
75
|
+
|
76
|
+
before_validation :set_sites_site_id
|
77
|
+
|
78
|
+
default_scope lambda {
|
79
|
+
site = GlobalRequestState.either_site
|
80
|
+
site = nil if GlobalRequestState.current_root
|
81
|
+
where(sites_site_id: site.id) if site
|
82
|
+
}
|
83
|
+
end
|
84
|
+
|
85
|
+
# rubocop:disable Metrics/MethodLength
|
86
|
+
def may_belong_to_tenant
|
87
|
+
column = columns.detect { |c| c.name == 'tenant_id' }
|
88
|
+
return if column.nil?
|
89
|
+
|
90
|
+
@tenancy_configuration[:belongs_to_tenant] = true
|
91
|
+
optional = column.null
|
92
|
+
belongs_to(:tenant, optional:)
|
93
|
+
|
94
|
+
before_validation :set_tenant_id
|
95
|
+
|
96
|
+
validate :tenant_matches_site
|
97
|
+
|
98
|
+
default_scope lambda {
|
99
|
+
site = GlobalRequestState.either_site
|
100
|
+
site = nil if GlobalRequestState.current_root
|
101
|
+
tenant = GlobalRequestState.either_tenant
|
102
|
+
tenant = nil if GlobalRequestState.either_admin
|
103
|
+
if site && tenant # for non admins (i.e. users)
|
104
|
+
where(sites_site_id: site.id, tenant_id: tenant.id)
|
105
|
+
elsif site # for site admins
|
106
|
+
where(sites_site_id: site.id)
|
107
|
+
elsif tenant
|
108
|
+
raise RuntimeError # where(tenant_id: tenant.id)
|
109
|
+
end
|
110
|
+
}
|
111
|
+
end
|
112
|
+
# rubocop:enable Metrics/MethodLength
|
113
|
+
|
114
|
+
def may_belong_to_workspace
|
115
|
+
column = columns.detect { |c| c.name == 'workspaces_workspace_id' }
|
116
|
+
return if column.nil?
|
117
|
+
|
118
|
+
@tenancy_configuration[:belongs_to_workspace] = true
|
119
|
+
optional = column.null
|
120
|
+
belongs_to(:workspaces_workspace, class_name: 'Workspaces::Workspace', optional:)
|
121
|
+
alias_method :workspace, :workspaces_workspace
|
122
|
+
alias_method :workspace=, :workspaces_workspace=
|
123
|
+
|
124
|
+
before_validation :set_workspaces_workspace_id
|
125
|
+
|
126
|
+
validate :workspaces_workspace_matches_site
|
127
|
+
end
|
128
|
+
|
129
|
+
def default_configuration
|
130
|
+
{
|
131
|
+
site_presence: :db,
|
132
|
+
tenant_presence: :db,
|
133
|
+
workspace_presence: :db,
|
134
|
+
site_source: :either_site,
|
135
|
+
tenant_source: :either_tenant,
|
136
|
+
workspace_source: :either_workspace
|
137
|
+
}
|
138
|
+
end
|
139
|
+
end
|
140
|
+
# rubocop:disable: Metrics/BlockLength
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bp3
|
4
|
+
module Core
|
5
|
+
# Bp3::Core::Test provides a convenience class for testing Bp3::Core
|
6
|
+
class Test
|
7
|
+
# to test Ransackable
|
8
|
+
include Ransackable
|
9
|
+
|
10
|
+
def self.column_names
|
11
|
+
%i[id name]
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.reflect_on_all_associations
|
15
|
+
[]
|
16
|
+
end
|
17
|
+
|
18
|
+
# to test Cookies
|
19
|
+
# first define this:
|
20
|
+
def self.before_action(_method_name); end
|
21
|
+
# then include Cookies
|
22
|
+
include Cookies
|
23
|
+
|
24
|
+
# to test Displayable
|
25
|
+
include Displayable
|
26
|
+
|
27
|
+
# to test FeatureFlags
|
28
|
+
include FeatureFlags
|
29
|
+
|
30
|
+
# to test Rqid
|
31
|
+
# first define this:
|
32
|
+
def self.before_create(_method_name); end
|
33
|
+
def self.belongs_to(_association, **options); end
|
34
|
+
def self.scope(_scope_name, _lambda); end
|
35
|
+
# then include Rqid
|
36
|
+
include Rqid
|
37
|
+
|
38
|
+
# to test Sqnr
|
39
|
+
include Sqnr
|
40
|
+
|
41
|
+
# to test Tenantable
|
42
|
+
# first define this:
|
43
|
+
def self.connection; end
|
44
|
+
# then include Tenantable
|
45
|
+
include Tenantable
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/bp3/core.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/concern'
|
4
|
+
require 'active_support/core_ext/module/attribute_accessors'
|
5
|
+
|
6
|
+
require_relative 'core/actions'
|
7
|
+
require_relative 'core/cookies'
|
8
|
+
require_relative 'core/displayable'
|
9
|
+
require_relative 'core/feature_flags'
|
10
|
+
require_relative 'core/ransackable'
|
11
|
+
require_relative 'core/settings'
|
12
|
+
require_relative 'core/tenantable'
|
13
|
+
require_relative 'core/rqid'
|
14
|
+
require_relative 'core/sqnr'
|
15
|
+
require_relative 'core/version'
|
16
|
+
|
17
|
+
module Bp3
|
18
|
+
module Core
|
19
|
+
end
|
20
|
+
end
|
data/lib/bp3-core.rb
ADDED