cnfs-cognito 0.0.1.alpha1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +28 -0
  4. data/Rakefile +24 -0
  5. data/app/controllers/chown_requests_controller.rb +4 -0
  6. data/app/controllers/chown_results_controller.rb +4 -0
  7. data/app/controllers/cognito/application_controller.rb +6 -0
  8. data/app/controllers/endpoints_controller.rb +4 -0
  9. data/app/controllers/identifiers_controller.rb +4 -0
  10. data/app/controllers/login_controller.rb +45 -0
  11. data/app/controllers/metabase_cards_controller.rb +4 -0
  12. data/app/controllers/metabase_token_controller.rb +46 -0
  13. data/app/controllers/pools_controller.rb +21 -0
  14. data/app/controllers/users_controller.rb +4 -0
  15. data/app/models/chown_request.rb +13 -0
  16. data/app/models/chown_result.rb +14 -0
  17. data/app/models/cognito/application_record.rb +7 -0
  18. data/app/models/endpoint.rb +6 -0
  19. data/app/models/identifier.rb +5 -0
  20. data/app/models/metabase_card.rb +6 -0
  21. data/app/models/platform_event_consumer.rb +8 -0
  22. data/app/models/pool.rb +6 -0
  23. data/app/models/tenant.rb +5 -0
  24. data/app/models/user.rb +50 -0
  25. data/app/models/user_pool.rb +6 -0
  26. data/app/operations/chown_request_process.rb +27 -0
  27. data/app/operations/pool_create.rb +65 -0
  28. data/app/operations/segments/age.rb +65 -0
  29. data/app/operations/segments/birthday.rb +49 -0
  30. data/app/operations/segments/except_ids.rb +28 -0
  31. data/app/operations/segments/gender.rb +35 -0
  32. data/app/operations/segments_apply.rb +40 -0
  33. data/app/policies/chown_request_policy.rb +4 -0
  34. data/app/policies/chown_result_policy.rb +4 -0
  35. data/app/policies/cognito/application_policy.rb +6 -0
  36. data/app/policies/endpoint_policy.rb +4 -0
  37. data/app/policies/identifier_policy.rb +4 -0
  38. data/app/policies/metabase_card_policy.rb +4 -0
  39. data/app/policies/pool_policy.rb +4 -0
  40. data/app/policies/tenant_policy.rb +5 -0
  41. data/app/policies/user_policy.rb +20 -0
  42. data/app/resources/chown_request_resource.rb +5 -0
  43. data/app/resources/chown_result_resource.rb +8 -0
  44. data/app/resources/cognito/application_resource.rb +7 -0
  45. data/app/resources/endpoint_resource.rb +49 -0
  46. data/app/resources/identifier_resource.rb +6 -0
  47. data/app/resources/metabase_card_resource.rb +5 -0
  48. data/app/resources/pool_resource.rb +30 -0
  49. data/app/resources/user_resource.rb +27 -0
  50. data/app/services/metabase/config.rb +16 -0
  51. data/app/services/metabase/token_generator.rb +36 -0
  52. data/config/environment.rb +0 -0
  53. data/config/routes.rb +14 -0
  54. data/config/sidekiq.yml +3 -0
  55. data/config/spring.rb +3 -0
  56. data/db/migrate/20190310013542_create_endpoints.rb +13 -0
  57. data/db/migrate/20190317072927_create_pools.rb +12 -0
  58. data/db/migrate/20190317073055_create_users.rb +18 -0
  59. data/db/migrate/20190317073139_create_identifiers.rb +14 -0
  60. data/db/migrate/20190317073328_create_user_pools.rb +12 -0
  61. data/db/migrate/20191105100356_create_chown_requests.rb +9 -0
  62. data/db/migrate/20191106023315_create_chown_results.rb +12 -0
  63. data/db/migrate/20191126011832_create_metabase_cards.rb +11 -0
  64. data/db/migrate/20191129055605_add_birthday_to_user.rb +5 -0
  65. data/db/migrate/20191205023159_add_gender_to_user.rb +5 -0
  66. data/db/migrate/20191210050613_add_system_generated_flag_to_pools.rb +5 -0
  67. data/db/seeds/development/data.seeds.rb +0 -0
  68. data/db/seeds/development/tenants.seeds.rb +7 -0
  69. data/db/seeds/development/users.seeds.rb +29 -0
  70. data/lib/ros/cognito.rb +16 -0
  71. data/lib/ros/cognito/engine.rb +53 -0
  72. data/lib/ros/cognito/version.rb +7 -0
  73. data/lib/tasks/ros/cognito_tasks.rake +16 -0
  74. 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,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ChownRequestPolicy < Cognito::ApplicationPolicy
4
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ChownResultPolicy < Cognito::ApplicationPolicy
4
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cognito
4
+ class ApplicationPolicy < ::ApplicationPolicy
5
+ end
6
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class EndpointPolicy < Cognito::ApplicationPolicy
4
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class IdentifierPolicy < Cognito::ApplicationPolicy
4
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class MetabaseCardPolicy < Cognito::ApplicationPolicy
4
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class PoolPolicy < Cognito::ApplicationPolicy
4
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TenantPolicy < Cognito::ApplicationPolicy
4
+ include Ros::TenantPolicyConcern
5
+ 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,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ChownRequestResource < Cognito::ApplicationResource
4
+ attributes :from_ids, :to_id
5
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ChownResultResource < Cognito::ApplicationResource
4
+ attributes :from_id, :to_id, :status, :service_name, :chown_request_id
5
+ has_one :chown_request
6
+
7
+ filters :from_id, :to_id, :status
8
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cognito
4
+ class ApplicationResource < ::ApplicationResource
5
+ abstract
6
+ end
7
+ 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,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ class IdentifierResource < Cognito::ApplicationResource
4
+ attributes :name, :value, :properties
5
+ has_one :user
6
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class MetabaseCardResource < Cognito::ApplicationResource
4
+ attributes :card_id, :identifier
5
+ 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