cnfs-cognito 0.0.1.alpha1
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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +28 -0
- data/Rakefile +24 -0
- data/app/controllers/chown_requests_controller.rb +4 -0
- data/app/controllers/chown_results_controller.rb +4 -0
- data/app/controllers/cognito/application_controller.rb +6 -0
- data/app/controllers/endpoints_controller.rb +4 -0
- data/app/controllers/identifiers_controller.rb +4 -0
- data/app/controllers/login_controller.rb +45 -0
- data/app/controllers/metabase_cards_controller.rb +4 -0
- data/app/controllers/metabase_token_controller.rb +46 -0
- data/app/controllers/pools_controller.rb +21 -0
- data/app/controllers/users_controller.rb +4 -0
- data/app/models/chown_request.rb +13 -0
- data/app/models/chown_result.rb +14 -0
- data/app/models/cognito/application_record.rb +7 -0
- data/app/models/endpoint.rb +6 -0
- data/app/models/identifier.rb +5 -0
- data/app/models/metabase_card.rb +6 -0
- data/app/models/platform_event_consumer.rb +8 -0
- data/app/models/pool.rb +6 -0
- data/app/models/tenant.rb +5 -0
- data/app/models/user.rb +50 -0
- data/app/models/user_pool.rb +6 -0
- data/app/operations/chown_request_process.rb +27 -0
- data/app/operations/pool_create.rb +65 -0
- data/app/operations/segments/age.rb +65 -0
- data/app/operations/segments/birthday.rb +49 -0
- data/app/operations/segments/except_ids.rb +28 -0
- data/app/operations/segments/gender.rb +35 -0
- data/app/operations/segments_apply.rb +40 -0
- data/app/policies/chown_request_policy.rb +4 -0
- data/app/policies/chown_result_policy.rb +4 -0
- data/app/policies/cognito/application_policy.rb +6 -0
- data/app/policies/endpoint_policy.rb +4 -0
- data/app/policies/identifier_policy.rb +4 -0
- data/app/policies/metabase_card_policy.rb +4 -0
- data/app/policies/pool_policy.rb +4 -0
- data/app/policies/tenant_policy.rb +5 -0
- data/app/policies/user_policy.rb +20 -0
- data/app/resources/chown_request_resource.rb +5 -0
- data/app/resources/chown_result_resource.rb +8 -0
- data/app/resources/cognito/application_resource.rb +7 -0
- data/app/resources/endpoint_resource.rb +49 -0
- data/app/resources/identifier_resource.rb +6 -0
- data/app/resources/metabase_card_resource.rb +5 -0
- data/app/resources/pool_resource.rb +30 -0
- data/app/resources/user_resource.rb +27 -0
- data/app/services/metabase/config.rb +16 -0
- data/app/services/metabase/token_generator.rb +36 -0
- data/config/environment.rb +0 -0
- data/config/routes.rb +14 -0
- data/config/sidekiq.yml +3 -0
- data/config/spring.rb +3 -0
- data/db/migrate/20190310013542_create_endpoints.rb +13 -0
- data/db/migrate/20190317072927_create_pools.rb +12 -0
- data/db/migrate/20190317073055_create_users.rb +18 -0
- data/db/migrate/20190317073139_create_identifiers.rb +14 -0
- data/db/migrate/20190317073328_create_user_pools.rb +12 -0
- data/db/migrate/20191105100356_create_chown_requests.rb +9 -0
- data/db/migrate/20191106023315_create_chown_results.rb +12 -0
- data/db/migrate/20191126011832_create_metabase_cards.rb +11 -0
- data/db/migrate/20191129055605_add_birthday_to_user.rb +5 -0
- data/db/migrate/20191205023159_add_gender_to_user.rb +5 -0
- data/db/migrate/20191210050613_add_system_generated_flag_to_pools.rb +5 -0
- data/db/seeds/development/data.seeds.rb +0 -0
- data/db/seeds/development/tenants.seeds.rb +7 -0
- data/db/seeds/development/users.seeds.rb +29 -0
- data/lib/ros/cognito.rb +16 -0
- data/lib/ros/cognito/engine.rb +53 -0
- data/lib/ros/cognito/version.rb +7 -0
- data/lib/tasks/ros/cognito_tasks.rake +16 -0
- metadata +162 -0
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Segments
|
4
|
+
class Age < Ros::ActivityBase
|
5
|
+
step :init
|
6
|
+
step :verify_segment
|
7
|
+
failed :incorrect_segment, Output(:success) => End(:failure)
|
8
|
+
step :translate_segment
|
9
|
+
step :apply_segment
|
10
|
+
failed :segment_not_applied, Output(:success) => End(:failure)
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def init(ctx, segment:, **)
|
15
|
+
ctx[:segment] = Array.wrap(segment)
|
16
|
+
ctx[:translated_segments] = []
|
17
|
+
end
|
18
|
+
|
19
|
+
def verify_segment(_ctx, segment:, **)
|
20
|
+
segment.all? { |s| segment_element_valid?(s) }
|
21
|
+
end
|
22
|
+
|
23
|
+
def incorrect_segment(_ctx, errors:, segment:, **)
|
24
|
+
errors.add(:segment, "Incorrect age segment value: #{segment}")
|
25
|
+
end
|
26
|
+
|
27
|
+
def translate_segment(_ctx, segment:, translated_segments:, **)
|
28
|
+
segment.each do |element|
|
29
|
+
translated_segments << case element
|
30
|
+
when Hash
|
31
|
+
el = element.with_indifferent_access
|
32
|
+
date_range(el['from'], el['to'])
|
33
|
+
when String, Integer
|
34
|
+
date_range(element, element)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def apply_segment(ctx, users:, translated_segments:, **)
|
40
|
+
ctx[:model] = users.where(birthday: translated_segments)
|
41
|
+
end
|
42
|
+
|
43
|
+
def segment_not_applied(_ctx, errors:, segment:, **)
|
44
|
+
errors.add(:model, "can't apply age segment: #{segment}")
|
45
|
+
end
|
46
|
+
|
47
|
+
def segment_element_valid?(element)
|
48
|
+
case element
|
49
|
+
when Hash
|
50
|
+
element.with_indifferent_access.keys.sort == %w[from to] && element.values.all? { |el| el.to_s.match(/^\d+$/) }
|
51
|
+
when String, Integer
|
52
|
+
element.to_s.match(/^\d+$/)
|
53
|
+
else
|
54
|
+
false
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def date_range(from, to, base_date = Time.zone.today)
|
59
|
+
Range.new(
|
60
|
+
base_date - to.to_i.years - 1.year + 1.day,
|
61
|
+
base_date - from.to_i.years
|
62
|
+
)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Segments
|
4
|
+
class Birthday < Ros::ActivityBase
|
5
|
+
step :init
|
6
|
+
step :verify_segment
|
7
|
+
failed :incorrect_segment, Output(:success) => End(:failure)
|
8
|
+
step :apply_segment
|
9
|
+
failed :segment_not_applied, Output(:success) => End(:failure)
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def init(ctx, segment:, **)
|
14
|
+
if segment.match(/^\d{2}$/)
|
15
|
+
ctx[:date] = Date.strptime(segment, '%m')
|
16
|
+
ctx[:segment] = 'this_month'
|
17
|
+
elsif segment.match(/^\d{2}-\d{2}$/)
|
18
|
+
ctx[:date] = Date.strptime(segment, '%m-%d')
|
19
|
+
ctx[:segment] = 'this_day'
|
20
|
+
else
|
21
|
+
ctx[:date] = Time.zone.today
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def verify_segment(_ctx, segment:, **)
|
26
|
+
%w[this_day this_month].include?(segment)
|
27
|
+
end
|
28
|
+
|
29
|
+
def incorrect_segment(_ctx, errors:, segment:, **)
|
30
|
+
errors.add(:segment, "Incorrect birthday segment value: #{segment}")
|
31
|
+
end
|
32
|
+
|
33
|
+
def apply_segment(ctx, users:, segment:, date:, **)
|
34
|
+
ctx[:model] = send(segment, users, date)
|
35
|
+
end
|
36
|
+
|
37
|
+
def segment_not_applied(_ctx, errors:, segment:, **)
|
38
|
+
errors.add(:model, "Can't apply birthday segment: #{segment}")
|
39
|
+
end
|
40
|
+
|
41
|
+
def this_day(users, date)
|
42
|
+
users.where("TO_CHAR(birthday, 'DD-MM') = TO_CHAR(DATE(?), 'DD-MM')", date)
|
43
|
+
end
|
44
|
+
|
45
|
+
def this_month(users, date)
|
46
|
+
users.where("TO_CHAR(birthday, 'MM') = TO_CHAR(DATE(?), 'MM')", date)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Segments
|
4
|
+
class ExceptIds < Ros::ActivityBase
|
5
|
+
step :verify_segment
|
6
|
+
failed :incorrect_segment, Output(:success) => End(:failure)
|
7
|
+
step :apply_segment
|
8
|
+
failed :segment_not_applied
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def verify_segment(_ctx, segment:, **)
|
13
|
+
segment.is_a?(Array)
|
14
|
+
end
|
15
|
+
|
16
|
+
def incorrect_segment(_ctx, errors:, segment:, **)
|
17
|
+
errors.add(:segment, "Incorrect except ids segment value: #{segment}")
|
18
|
+
end
|
19
|
+
|
20
|
+
def apply_segment(ctx, users:, segment:, **)
|
21
|
+
ctx[:model] = users.where.not(id: segment)
|
22
|
+
end
|
23
|
+
|
24
|
+
def segment_not_applied(_ctx, errors:, segment:, **)
|
25
|
+
errors.add(:model, "Can't apply except ids segment: #{segment}")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Segments
|
4
|
+
class Gender < Ros::ActivityBase
|
5
|
+
step :verify_segment
|
6
|
+
failed :incorrect_segment, Output(:success) => End(:failure)
|
7
|
+
step :apply_segment
|
8
|
+
failed :segment_not_applied, Output(:success) => End(:failure)
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def verify_segment(_ctx, segment:, **)
|
13
|
+
case segment
|
14
|
+
when Array
|
15
|
+
(segment - %w[male female other]).empty?
|
16
|
+
when String
|
17
|
+
%w[male female other any].include?(segment)
|
18
|
+
else
|
19
|
+
false
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def incorrect_segment(_ctx, errors:, segment:, **)
|
24
|
+
errors.add(:segment, "Incorrect gender segment value: #{segment}")
|
25
|
+
end
|
26
|
+
|
27
|
+
def apply_segment(ctx, users:, segment:, **)
|
28
|
+
ctx[:model] = segment == 'any' ? users : users.where(gender: segment)
|
29
|
+
end
|
30
|
+
|
31
|
+
def segment_not_applied(_ctx, errors:, segment:, **)
|
32
|
+
errors.add(:model, "Can't apply gender segment: #{segment}")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class SegmentsApply < Ros::ActivityBase
|
4
|
+
step :init
|
5
|
+
step :apply_segments
|
6
|
+
failed :unset_model
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def init(ctx, users:, **)
|
11
|
+
ctx[:model] = users
|
12
|
+
end
|
13
|
+
|
14
|
+
def apply_segments(ctx, model:, segments:, errors:, **)
|
15
|
+
segments.each do |segment_key, segment_value|
|
16
|
+
res = apply_segment(segment_key, segment_value, model, errors)
|
17
|
+
return false if res.nil?
|
18
|
+
|
19
|
+
if res.failure?
|
20
|
+
ctx[:errors] = res.errors
|
21
|
+
return false
|
22
|
+
end
|
23
|
+
|
24
|
+
model = res.model
|
25
|
+
end
|
26
|
+
ctx[:model] = model
|
27
|
+
end
|
28
|
+
|
29
|
+
def apply_segment(segment_key, segment_value, users, errors)
|
30
|
+
segment_class = "Segments::#{segment_key.classify}".constantize
|
31
|
+
segment_class.call(users: users, segment: segment_value)
|
32
|
+
rescue NameError => _e
|
33
|
+
errors.add(:segment, "can't find segmentation class")
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
|
37
|
+
def unset_model(ctx, **)
|
38
|
+
ctx[:model] = nil
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class UserPolicy < Cognito::ApplicationPolicy
|
4
|
+
class Scope
|
5
|
+
attr_reader :user, :scope
|
6
|
+
|
7
|
+
def initialize(user, scope)
|
8
|
+
@user = user
|
9
|
+
@scope = scope
|
10
|
+
end
|
11
|
+
|
12
|
+
def resolve
|
13
|
+
if user.cognito_user_id
|
14
|
+
scope.where(id: user.cognito_user_id)
|
15
|
+
else
|
16
|
+
scope.all
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class EndpointResource < Cognito::ApplicationResource
|
4
|
+
attributes :url, :properties, :target_type, :target_id
|
5
|
+
|
6
|
+
filters :target_type, :target_id
|
7
|
+
filter :url
|
8
|
+
|
9
|
+
def custom_links(options)
|
10
|
+
uri = URI(options[:serializer].link_builder.self_link(self))
|
11
|
+
{ target: target_uri(uri) }
|
12
|
+
end
|
13
|
+
|
14
|
+
def target_uri(uri)
|
15
|
+
return '' unless @model.target_type
|
16
|
+
|
17
|
+
service, model = @model.target_type.underscore.split('/')
|
18
|
+
case Settings.external_connection.type
|
19
|
+
when 'service'
|
20
|
+
uri.host = uri.host.gsub(Settings.service.name, service)
|
21
|
+
uri.path = ['', model, @model.target_id].join('/')
|
22
|
+
when 'path'
|
23
|
+
uri.path = ['', service, model, @model.target_id].join('/')
|
24
|
+
when 'port'
|
25
|
+
# TODO: Test for whether service_endpoint is nil
|
26
|
+
uri.port = URI(Ros::Sdk.service_endpoints[service]).port
|
27
|
+
when 'host'
|
28
|
+
uri.host = URI(Ros::Sdk.service_endpoints[service]).host
|
29
|
+
end
|
30
|
+
uri.to_s
|
31
|
+
end
|
32
|
+
|
33
|
+
def fetchable_fields
|
34
|
+
super - [:urn]
|
35
|
+
end
|
36
|
+
|
37
|
+
# def self.updatable_fields(context)
|
38
|
+
# super - [:full_name]
|
39
|
+
# end
|
40
|
+
|
41
|
+
# def self.creatable_fields(context)
|
42
|
+
# super - [:full_name]
|
43
|
+
# end
|
44
|
+
# def resource; [@model.target_type.underscore.split('/').last, @model.target_id].join('/') end
|
45
|
+
|
46
|
+
# def self.sortable_fields(context)
|
47
|
+
# super(context) - [:body]
|
48
|
+
# end
|
49
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class PoolResource < Cognito::ApplicationResource
|
4
|
+
attributes :name, :properties, :user_count, :system_generated
|
5
|
+
has_many :users
|
6
|
+
|
7
|
+
filter :query, apply: lambda { |records, value, _options|
|
8
|
+
query_by_id = 'pools.id IN (:id_query)'
|
9
|
+
query_by_non_id_attrs = %w[name]
|
10
|
+
.map { |field| "#{field} ILIKE :ilike_query" }
|
11
|
+
.join(' OR ')
|
12
|
+
|
13
|
+
filter_fields = /^\d+$/.match?(value[0]) ? query_by_id : query_by_non_id_attrs
|
14
|
+
records.where(filter_fields, id_query: value[0], ilike_query: "%#{value[0]}%")
|
15
|
+
}
|
16
|
+
|
17
|
+
filter :system_generated
|
18
|
+
|
19
|
+
def self.updatable_fields(context)
|
20
|
+
super - %i[user_count]
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.creatable_fields(context)
|
24
|
+
super - %i[user_count]
|
25
|
+
end
|
26
|
+
|
27
|
+
def user_count
|
28
|
+
users.size
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class UserResource < Cognito::ApplicationResource
|
4
|
+
attributes :title, :first_name, :last_name, :phone_number, :email_address,
|
5
|
+
:primary_identifier, :properties, :anonymous, :birthday, :gender
|
6
|
+
filter :primary_identifier
|
7
|
+
|
8
|
+
filter :query, apply: lambda { |records, value, _options|
|
9
|
+
searchable_columns = ['primary_identifier', 'first_name', 'last_name', 'phone_number', 'email_address',
|
10
|
+
"first_name || ' ' || last_name", "last_name || ' ' || first_name"]
|
11
|
+
query_by_non_id_attrs = searchable_columns.map { |field| "#{field} ILIKE :non_id_query" }.join(' OR ')
|
12
|
+
|
13
|
+
results = records.where(query_by_non_id_attrs, non_id_query: "%#{value[0]}%")
|
14
|
+
results = results.or(records.where(id: value[0])) if /^(\d)+$/.match?(value[0])
|
15
|
+
results
|
16
|
+
}
|
17
|
+
|
18
|
+
filter :segments, apply: lambda { |records, value, _options|
|
19
|
+
SegmentsApply.call(users: records, segments: value[0].permit!.to_h).model
|
20
|
+
}
|
21
|
+
|
22
|
+
filter :pool_id, apply: lambda { |records, value, _options|
|
23
|
+
records.joins(:pools).where(pools: { id: value })
|
24
|
+
}
|
25
|
+
|
26
|
+
has_many :pools
|
27
|
+
end
|