maestrano-connector-rails 1.2.1 → 1.2.2

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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +41 -0
  3. data/.rubocop_todo.yml +180 -0
  4. data/.ruby-version +1 -1
  5. data/CODESHIP.md +3 -1
  6. data/Gemfile +16 -10
  7. data/Rakefile +12 -12
  8. data/VERSION +1 -1
  9. data/app/controllers/maestrano/account/group_users_controller.rb +5 -7
  10. data/app/controllers/maestrano/account/groups_controller.rb +5 -7
  11. data/app/controllers/maestrano/application_controller.rb +1 -1
  12. data/app/controllers/maestrano/auth/saml_controller.rb +5 -10
  13. data/app/controllers/maestrano/connec_controller.rb +12 -11
  14. data/app/controllers/maestrano/sessions_controller.rb +1 -1
  15. data/app/controllers/maestrano/synchronizations_controller.rb +7 -9
  16. data/app/controllers/version_controller.rb +9 -0
  17. data/app/helpers/maestrano/connector/rails/session_helper.rb +0 -2
  18. data/app/jobs/maestrano/connector/rails/all_synchronizations_job.rb +2 -2
  19. data/app/jobs/maestrano/connector/rails/push_to_connec_job.rb +8 -7
  20. data/app/jobs/maestrano/connector/rails/push_to_connec_worker.rb +6 -4
  21. data/app/jobs/maestrano/connector/rails/synchronization_job.rb +10 -9
  22. data/app/models/maestrano/connector/rails/complex_entity.rb +1 -1
  23. data/app/models/maestrano/connector/rails/concerns/complex_entity.rb +10 -12
  24. data/app/models/maestrano/connector/rails/concerns/connec_helper.rb +20 -25
  25. data/app/models/maestrano/connector/rails/concerns/connector_logger.rb +1 -1
  26. data/app/models/maestrano/connector/rails/concerns/entity.rb +63 -69
  27. data/app/models/maestrano/connector/rails/concerns/entity_base.rb +3 -3
  28. data/app/models/maestrano/connector/rails/concerns/external.rb +2 -2
  29. data/app/models/maestrano/connector/rails/concerns/sub_entity_base.rb +13 -15
  30. data/app/models/maestrano/connector/rails/connector_logger.rb +1 -1
  31. data/app/models/maestrano/connector/rails/entity.rb +1 -1
  32. data/app/models/maestrano/connector/rails/external.rb +1 -1
  33. data/app/models/maestrano/connector/rails/id_map.rb +1 -2
  34. data/app/models/maestrano/connector/rails/organization.rb +12 -14
  35. data/app/models/maestrano/connector/rails/sub_entity_base.rb +1 -1
  36. data/app/models/maestrano/connector/rails/synchronization.rb +17 -15
  37. data/app/models/maestrano/connector/rails/user.rb +1 -2
  38. data/app/models/maestrano/connector/rails/user_organization_rel.rb +1 -2
  39. data/config/routes.rb +4 -2
  40. data/lib/maestrano/connector/rails.rb +17 -2
  41. data/lib/maestrano_connector_rails.rb +1 -0
  42. data/maestrano-connector-rails.gemspec +32 -13
  43. data/release_notes.md +5 -0
  44. data/spec/controllers/version_controller_spec.rb +17 -0
  45. data/spec/dummy/config/application.rb +1 -1
  46. data/spec/jobs/push_to_connec_worker_spec.rb +16 -5
  47. data/spec/models/synchronization_spec.rb +9 -9
  48. data/spec/models/user_organization_rel_spec.rb +1 -1
  49. data/template/maestrano-connector-template.rb +2 -17
  50. metadata +90 -16
  51. data/lib/maestrano-connector-rails.rb +0 -1
@@ -12,4 +12,4 @@ module Maestrano
12
12
  redirect_to root_url
13
13
  end
14
14
  end
15
- end
15
+ end
@@ -2,7 +2,7 @@ class Maestrano::SynchronizationsController < Maestrano::Rails::WebHookControlle
2
2
  def show
3
3
  uid = params[:id]
4
4
  organization = Maestrano::Connector::Rails::Organization.find_by_uid(uid)
5
- return render json: { errors: {message: "Organization not found", code: 404} }, status: :not_found unless organization
5
+ return render json: {errors: {message: "Organization not found", code: 404}}, status: :not_found unless organization
6
6
 
7
7
  h = {
8
8
  group_id: organization.uid,
@@ -12,11 +12,9 @@ class Maestrano::SynchronizationsController < Maestrano::Rails::WebHookControlle
12
12
  last_sync = organization.synchronizations.last
13
13
  if last_sync
14
14
  h.merge!(
15
- {
16
- status: last_sync.status,
17
- message: last_sync.message,
18
- updated_at: last_sync.updated_at
19
- }
15
+ status: last_sync.status,
16
+ message: last_sync.message,
17
+ updated_at: last_sync.updated_at
20
18
  )
21
19
  end
22
20
 
@@ -27,7 +25,7 @@ class Maestrano::SynchronizationsController < Maestrano::Rails::WebHookControlle
27
25
  uid = params[:group_id]
28
26
  opts = params[:opts] || {}
29
27
  organization = Maestrano::Connector::Rails::Organization.find_by_uid(uid)
30
- return render json: { errors: {message: "Organization not found", code: 404} }, status: :not_found unless organization
28
+ return render json: {errors: {message: "Organization not found", code: 404}}, status: :not_found unless organization
31
29
 
32
30
  Maestrano::Connector::Rails::SynchronizationJob.perform_later(organization, opts.with_indifferent_access)
33
31
  head :created
@@ -36,11 +34,11 @@ class Maestrano::SynchronizationsController < Maestrano::Rails::WebHookControlle
36
34
  def toggle_sync
37
35
  uid = params[:group_id]
38
36
  organization = Maestrano::Connector::Rails::Organization.find_by_uid(uid)
39
- return render json: { errors: {message: "Organization not found", code: 404} }, status: :not_found unless organization
37
+ return render json: {errors: {message: "Organization not found", code: 404}}, status: :not_found unless organization
40
38
 
41
39
  organization.toggle(:sync_enabled)
42
40
  organization.save
43
41
 
44
42
  render json: {sync_enabled: organization.sync_enabled}
45
43
  end
46
- end
44
+ end
@@ -0,0 +1,9 @@
1
+ class VersionController < ApplicationController
2
+ def index
3
+ framework_version = Gem.loaded_specs['maestrano-connector-rails'].version.version
4
+ respond_to do |format|
5
+ format.html { render text: "framework_version=#{framework_version}\n" }
6
+ format.json { render json: {framework_version: framework_version} }
7
+ end
8
+ end
9
+ end
@@ -1,6 +1,5 @@
1
1
  module Maestrano::Connector::Rails
2
2
  module SessionHelper
3
-
4
3
  def is_admin?(user, organization)
5
4
  organization.member?(user) && session[:"role_#{organization.uid}"] && ['Admin', 'Super Admin'].include?(session[:"role_#{organization.uid}"])
6
5
  end
@@ -16,6 +15,5 @@ module Maestrano::Connector::Rails
16
15
  def is_admin
17
16
  @is_admin ||= current_user && current_organization && is_admin?(current_user, current_organization)
18
17
  end
19
-
20
18
  end
21
19
  end
@@ -3,11 +3,11 @@ module Maestrano::Connector::Rails
3
3
  queue_as :default
4
4
 
5
5
  # Trigger synchronization of all active organizations
6
- def perform(name=nil, count=nil)
6
+ def perform(name = nil, count = nil)
7
7
  Maestrano::Connector::Rails::Organization.where.not(oauth_provider: nil, encrypted_oauth_token: nil).each do |o|
8
8
  next unless [true, 1].include?(o.sync_enabled)
9
9
  Maestrano::Connector::Rails::SynchronizationJob.perform_later(o, {})
10
10
  end
11
11
  end
12
12
  end
13
- end
13
+ end
@@ -3,7 +3,7 @@ module Maestrano::Connector::Rails
3
3
  queue_as :default
4
4
 
5
5
  # expected hash: {"external_entity_name1" => [entity1, entity2], "external_entity_name2" => []}
6
- def perform(organization, entities_hash, opts={})
6
+ def perform(organization, entities_hash, opts = {})
7
7
  return unless organization.sync_enabled && organization.oauth_uid
8
8
 
9
9
  connec_client = Maestrano::Connector::Rails::ConnecHelper.get_client(organization)
@@ -18,11 +18,11 @@ module Maestrano::Connector::Rails
18
18
 
19
19
  entity_instance.before_sync(last_synchronization_date)
20
20
  # Build expected input for consolidate_and_map_data
21
- if entity_instance_hash[:is_complex]
22
- mapped_entities = entity_instance.consolidate_and_map_data(ComplexEntity.build_empty_hash(entity_instance.class.connec_entities_names), ComplexEntity.build_hash_with_entities(entity_instance.class.external_entities_names, external_entity_name, lambda{|name| name}, entities))
23
- else
24
- mapped_entities = entity_instance.consolidate_and_map_data([], entities)
25
- end
21
+ mapped_entities = if entity_instance_hash[:is_complex]
22
+ entity_instance.consolidate_and_map_data(ComplexEntity.build_empty_hash(entity_instance.class.connec_entities_names), ComplexEntity.build_hash_with_entities(entity_instance.class.external_entities_names, external_entity_name, ->(name) { name }, entities))
23
+ else
24
+ entity_instance.consolidate_and_map_data([], entities)
25
+ end
26
26
  entity_instance.push_entities_to_connec(mapped_entities[:external_entities])
27
27
 
28
28
  entity_instance.after_sync(last_synchronization_date)
@@ -33,6 +33,7 @@ module Maestrano::Connector::Rails
33
33
  end
34
34
 
35
35
  private
36
+
36
37
  def find_entity_instance(entity_name, organization, connec_client, external_client, opts)
37
38
  Maestrano::Connector::Rails::External.entities_list.each do |entity_name_from_list|
38
39
  clazz = "Entities::#{entity_name_from_list.singularize.titleize.split.join}".constantize
@@ -45,4 +46,4 @@ module Maestrano::Connector::Rails
45
46
  nil
46
47
  end
47
48
  end
48
- end
49
+ end
@@ -7,13 +7,15 @@ module Maestrano::Connector::Rails
7
7
  sidekiq_options unique: :while_executing, unique_args: :unique_args
8
8
 
9
9
  def self.unique_args(args)
10
- organization = args[0]
10
+ organization_id = args[0]
11
11
  entities_hash = args[1]
12
- return[organization.id, entities_hash.keys.sort]
12
+
13
+ [organization_id, entities_hash.keys.sort]
13
14
  end
14
15
 
15
- def perform(organization, entities_hash, opts={})
16
+ def perform(organization_id, entities_hash, opts = {})
17
+ organization = Organization.find(organization_id)
16
18
  PushToConnecJob.new.perform(organization, entities_hash, opts)
17
19
  end
18
20
  end
19
- end
21
+ end
@@ -7,19 +7,19 @@ module Maestrano::Connector::Rails
7
7
  # * :only_entities => [person, tasks_list]
8
8
  # * :full_sync => true synchronization is performed without date filtering
9
9
  # * :connec_preemption => true|false : preemption is always|never given to connec in case of conflict (if not set, the most recently updated entity is kept)
10
- def perform(organization, opts={})
10
+ def perform(organization, opts = {})
11
11
  return unless organization.sync_enabled
12
12
 
13
13
  # Check if previous synchronization is still running
14
14
  if Synchronization.where(organization_id: organization.id, status: 'RUNNING').where(created_at: (30.minutes.ago..Time.now)).exists?
15
- ConnectorLogger.log('info', organization, "Synchronization skipped: Previous synchronization is still running")
15
+ ConnectorLogger.log('info', organization, 'Synchronization skipped: Previous synchronization is still running')
16
16
  return
17
17
  end
18
18
 
19
19
  # Check if recovery mode: last 3 synchronizations have failed
20
20
  if !opts[:forced] && organization.last_three_synchronizations_failed? \
21
21
  && organization.synchronizations.order(created_at: :desc).limit(1).first.updated_at > 1.day.ago
22
- ConnectorLogger.log('info', organization, "Synchronization skipped: Recovery mode (three previous synchronizations have failed)")
22
+ ConnectorLogger.log('info', organization, 'Synchronization skipped: Recovery mode (three previous synchronizations have failed)')
23
23
  return
24
24
  end
25
25
 
@@ -37,8 +37,8 @@ module Maestrano::Connector::Rails
37
37
  # We do a doube sync: only from external, then only from connec!
38
38
  # We also do batched sync as the first one can be quite huge
39
39
  if last_synchronization.nil?
40
- ConnectorLogger.log('info', organization, "First synchronization ever. Doing two half syncs to allow smart merging to work its magic.")
41
- organization.synchronized_entities.select{|k, v| v}.keys.each do |entity|
40
+ ConnectorLogger.log('info', organization, 'First synchronization ever. Doing two half syncs to allow smart merging to work its magic.')
41
+ organization.synchronized_entities.select { |k, v| v }.keys.each do |entity|
42
42
  ConnectorLogger.log('info', organization, "First synchronization ever. Doing half sync from external for #{entity}.")
43
43
  first_sync_entity(entity.to_s, organization, connec_client, external_client, last_synchronization_date, opts, true)
44
44
  ConnectorLogger.log('info', organization, "First synchronization ever. Doing half sync from Connec! for #{entity}.")
@@ -52,7 +52,7 @@ module Maestrano::Connector::Rails
52
52
  sync_entity(entity, organization, connec_client, external_client, last_synchronization_date, opts)
53
53
  end
54
54
  else
55
- organization.synchronized_entities.select{|k, v| v}.keys.each do |entity|
55
+ organization.synchronized_entities.select { |_k, v| v }.keys.each do |entity|
56
56
  sync_entity(entity.to_s, organization, connec_client, external_client, last_synchronization_date, opts)
57
57
  end
58
58
  end
@@ -78,7 +78,7 @@ module Maestrano::Connector::Rails
78
78
  entities_count = limit
79
79
 
80
80
  h = {__limit: limit}
81
- external ? h.merge!(__skip_connec: true) : h.merge!(__skip_external: true)
81
+ external ? h[:__skip_connec] = true : h[:__skip_external] = true
82
82
  entity_instance = instanciate_entity(entity_name, organization, connec_client, external_client, opts.merge(h))
83
83
 
84
84
  # IF entities_count > limit
@@ -87,7 +87,7 @@ module Maestrano::Connector::Rails
87
87
  # No need to fetch it a second Time
88
88
  # ELSIF entities_count < limit
89
89
  # No more entities to fetch
90
- while entities_count == limit do
90
+ while entities_count == limit
91
91
  entity_instance.opts_merge!(__skip: skip)
92
92
  entities_count = perform_sync(entity_instance, last_synchronization_date, external)
93
93
  skip += limit
@@ -95,6 +95,7 @@ module Maestrano::Connector::Rails
95
95
  end
96
96
 
97
97
  private
98
+
98
99
  def instanciate_entity(entity_name, organization, connec_client, external_client, opts)
99
100
  "Entities::#{entity_name.titleize.split.join}".constantize.new(organization, connec_client, external_client, opts.dup)
100
101
  end
@@ -112,4 +113,4 @@ module Maestrano::Connector::Rails
112
113
  external ? entity_instance.class.count_entities(external_entities) : entity_instance.class.count_entities(connec_entities)
113
114
  end
114
115
  end
115
- end
116
+ end
@@ -2,4 +2,4 @@ module Maestrano::Connector::Rails
2
2
  class ComplexEntity < EntityBase
3
3
  include Maestrano::Connector::Rails::Concerns::ComplexEntity
4
4
  end
5
- end
5
+ end
@@ -7,11 +7,11 @@ module Maestrano::Connector::Rails::Concerns::ComplexEntity
7
7
  # -------------------------------------------------------------
8
8
  module ClassMethods
9
9
  def connec_entities_names
10
- raise "Not implemented"
10
+ raise 'Not implemented'
11
11
  end
12
12
 
13
13
  def external_entities_names
14
- raise "Not implemented"
14
+ raise 'Not implemented'
15
15
  end
16
16
 
17
17
  def count_entities(entities)
@@ -33,7 +33,7 @@ module Maestrano::Connector::Rails::Concerns::ComplexEntity
33
33
  # }
34
34
  # }
35
35
  def connec_model_to_external_model(connec_hash_of_entities)
36
- raise "Not implemented"
36
+ raise 'Not implemented'
37
37
  end
38
38
 
39
39
  # input : {
@@ -50,13 +50,13 @@ module Maestrano::Connector::Rails::Concerns::ComplexEntity
50
50
  # }
51
51
  # }
52
52
  def external_model_to_connec_model(external_hash_of_entities)
53
- raise "Not implemented"
53
+ raise 'Not implemented'
54
54
  end
55
55
 
56
56
  # -------------------------------------------------------------
57
57
  # Entity equivalent methods
58
58
  # -------------------------------------------------------------
59
- def get_connec_entities(last_synchronization_date=nil)
59
+ def get_connec_entities(last_synchronization_date = nil)
60
60
  entities = ActiveSupport::HashWithIndifferentAccess.new
61
61
 
62
62
  self.class.connec_entities_names.each do |connec_entity_name|
@@ -66,7 +66,7 @@ module Maestrano::Connector::Rails::Concerns::ComplexEntity
66
66
  entities
67
67
  end
68
68
 
69
- def get_external_entities_wrapper(last_synchronization_date=nil)
69
+ def get_external_entities_wrapper(last_synchronization_date = nil)
70
70
  entities = ActiveSupport::HashWithIndifferentAccess.new
71
71
 
72
72
  self.class.external_entities_names.each do |external_entity_name|
@@ -83,13 +83,12 @@ module Maestrano::Connector::Rails::Concerns::ComplexEntity
83
83
  mapped_connec_entities = consolidate_and_map_connec_entities(modeled_connec_entities, modeled_external_entities)
84
84
  mapped_external_entities = consolidate_and_map_external_entities(modeled_external_entities)
85
85
 
86
- return {connec_entities: mapped_connec_entities, external_entities: mapped_external_entities}
86
+ {connec_entities: mapped_connec_entities, external_entities: mapped_external_entities}
87
87
  end
88
88
 
89
89
  def consolidate_and_map_connec_entities(modeled_connec_entities, modeled_external_entities)
90
90
  modeled_connec_entities.each do |connec_entity_name, entities_in_external_model|
91
91
  entities_in_external_model.each do |external_entity_name, entities|
92
-
93
92
  sub_entity_instance = instantiate_sub_entity_instance(connec_entity_name)
94
93
  equivalent_external_entities = (modeled_external_entities[external_entity_name] && modeled_external_entities[external_entity_name][connec_entity_name]) || []
95
94
 
@@ -128,7 +127,6 @@ module Maestrano::Connector::Rails::Concerns::ComplexEntity
128
127
  end
129
128
  end
130
129
 
131
-
132
130
  def push_entities_to_external(mapped_connec_entities_with_idmaps)
133
131
  mapped_connec_entities_with_idmaps.each do |connec_entity_name, entities_in_external_model|
134
132
  sub_entity_instance = instantiate_sub_entity_instance(connec_entity_name)
@@ -148,13 +146,13 @@ module Maestrano::Connector::Rails::Concerns::ComplexEntity
148
146
  module ClassMethods
149
147
  # output : {entities_names[0] => [], entities_names[1] => []}
150
148
  def build_empty_hash(entities_names)
151
- Hash[ *entities_names.collect{|name| [ name, []]}.flatten(1) ]
149
+ Hash[*entities_names.collect { |name| [name, []] }.flatten(1)]
152
150
  end
153
151
 
154
152
  # output: {entities_name[0] => [], entities_name[1] => entities}
155
153
  # with proc.call(entities_name[1] == entity_name)
156
154
  def build_hash_with_entities(entities_name, entity_name, proc, entities)
157
- Hash[ *entities_name.collect{|name| proc.call(name) == entity_name ? [name, entities] : [ name, []]}.flatten(1) ]
155
+ Hash[*entities_name.collect { |name| proc.call(name) == entity_name ? [name, entities] : [name, []] }.flatten(1)]
158
156
  end
159
157
  end
160
- end
158
+ end
@@ -25,7 +25,7 @@ module Maestrano::Connector::Rails::Concerns::ConnecHelper
25
25
  end
26
26
  @@connec_version
27
27
  end
28
-
28
+
29
29
  # Replace the ids arrays by the external id
30
30
  # If a reference has no id for this oauth_provider and oauth_uid but has one for connec returns nil
31
31
  def unfold_references(connec_entity, references, organization)
@@ -33,13 +33,9 @@ module Maestrano::Connector::Rails::Concerns::ConnecHelper
33
33
  not_nil = true
34
34
 
35
35
  # Id
36
- id = unfolded_connec_entity['id'].find{|id| id['provider'] == organization.oauth_provider && id['realm'] == organization.oauth_uid}
37
- unfolded_connec_entity[:__connec_id] = unfolded_connec_entity['id'].find{|id| id['provider'] == 'connec'}['id']
38
- if id
39
- unfolded_connec_entity['id'] = id['id']
40
- else
41
- unfolded_connec_entity['id'] = nil
42
- end
36
+ id_hash = unfolded_connec_entity['id'].find { |id| id['provider'] == organization.oauth_provider && id['realm'] == organization.oauth_uid }
37
+ unfolded_connec_entity[:__connec_id] = unfolded_connec_entity['id'].find { |id| id['provider'] == 'connec' }['id']
38
+ unfolded_connec_entity['id'] = id_hash ? id_hash['id'] : nil
43
39
 
44
40
  # Other refs
45
41
  references.each do |reference|
@@ -67,20 +63,19 @@ module Maestrano::Connector::Rails::Concerns::ConnecHelper
67
63
  def fold_references_helper(entity, array_of_refs, organization)
68
64
  ref = array_of_refs.shift
69
65
  field = entity[ref]
66
+ return if field.blank?
70
67
 
71
68
  # Follow embedment path, remplace if it's not an array or a hash
72
- unless field.blank?
73
- case field
74
- when Array
75
- field.each do |f|
76
- fold_references_helper(f, array_of_refs.dup, organization)
77
- end
78
- when HashWithIndifferentAccess
79
- fold_references_helper(entity[ref], array_of_refs, organization)
80
- else
81
- id = field
82
- entity[ref] = [id_hash(id, organization)]
69
+ case field
70
+ when Array
71
+ field.each do |f|
72
+ fold_references_helper(f, array_of_refs.dup, organization)
83
73
  end
74
+ when HashWithIndifferentAccess
75
+ fold_references_helper(entity[ref], array_of_refs, organization)
76
+ else
77
+ id = field
78
+ entity[ref] = [id_hash(id, organization)]
84
79
  end
85
80
  end
86
81
 
@@ -89,10 +84,11 @@ module Maestrano::Connector::Rails::Concerns::ConnecHelper
89
84
  field = entity[ref]
90
85
 
91
86
  # Unfold the id
92
- if array_of_refs.empty?
93
- if id = field && field.find{|id| id[:provider] == organization.oauth_provider && id[:realm] == organization.oauth_uid}
94
- entity[ref] = id['id']
95
- elsif field && field.find{|id| id[:provider] == 'connec'}
87
+ if array_of_refs.empty? && field
88
+ id_hash = field.find { |id| id[:provider] == organization.oauth_provider && id[:realm] == organization.oauth_uid }
89
+ if id_hash
90
+ entity[ref] = id_hash['id']
91
+ elsif field.find { |id| id[:provider] == 'connec' } # Should always be true as ids will always contain a connec id
96
92
  # We may enqueue a fetch on the endpoint of the missing association, followed by a re-fetch on this one.
97
93
  # However it's expected to be an edge case, so for now we rely on the fact that the webhooks should be relativly in order.
98
94
  # Worst case it'll be done on following sync
@@ -114,6 +110,5 @@ module Maestrano::Connector::Rails::Concerns::ConnecHelper
114
110
  end
115
111
  true
116
112
  end
117
-
118
113
  end
119
- end
114
+ end
@@ -6,4 +6,4 @@ module Maestrano::Connector::Rails::Concerns::ConnectorLogger
6
6
  Rails.logger.method(level).call("org: #{organization.uid} (#{organization.tenant}). Msg: #{msg}")
7
7
  end
8
8
  end
9
- end
9
+ end
@@ -19,9 +19,11 @@ module Maestrano::Connector::Rails::Concerns::Entity
19
19
  def find_or_create_idmap(organization_and_id)
20
20
  Maestrano::Connector::Rails::IdMap.find_or_create_by(names_hash.merge(organization_and_id))
21
21
  end
22
+
22
23
  def find_idmap(organization_and_id)
23
24
  Maestrano::Connector::Rails::IdMap.find_by(names_hash.merge(organization_and_id))
24
25
  end
26
+
25
27
  def create_idmap(organization_and_id)
26
28
  Maestrano::Connector::Rails::IdMap.create(names_hash.merge(organization_and_id))
27
29
  end
@@ -45,25 +47,25 @@ module Maestrano::Connector::Rails::Concerns::Entity
45
47
  # External methods
46
48
  # ----------------------------------------------
47
49
  def id_from_external_entity_hash(entity)
48
- raise "Not implemented"
50
+ raise 'Not implemented'
49
51
  end
50
52
 
51
53
  def last_update_date_from_external_entity_hash(entity)
52
- raise "Not implemented"
54
+ raise 'Not implemented'
53
55
  end
54
56
 
55
57
  def creation_date_from_external_entity_hash(entity)
56
- raise "Not implemented"
58
+ raise 'Not implemented'
57
59
  end
58
60
 
59
61
  # Return a string representing the object from a connec! entity hash
60
62
  def object_name_from_connec_entity_hash(entity)
61
- raise "Not implemented"
63
+ raise 'Not implemented'
62
64
  end
63
65
 
64
66
  # Return a string representing the object from an external entity hash
65
67
  def object_name_from_external_entity_hash(entity)
66
- raise "Not implemented"
68
+ raise 'Not implemented'
67
69
  end
68
70
 
69
71
  # Returns a boolean
@@ -71,6 +73,7 @@ module Maestrano::Connector::Rails::Concerns::Entity
71
73
  def inactive_from_external_entity_hash?(entity)
72
74
  false
73
75
  end
76
+
74
77
  # ----------------------------------------------
75
78
  # Entity specific methods
76
79
  # Those methods need to be define in each entity
@@ -82,17 +85,17 @@ module Maestrano::Connector::Rails::Concerns::Entity
82
85
 
83
86
  # Entity name in Connec!
84
87
  def connec_entity_name
85
- raise "Not implemented"
88
+ raise 'Not implemented'
86
89
  end
87
90
 
88
91
  # Entity name in external system
89
92
  def external_entity_name
90
- raise "Not implemented"
93
+ raise 'Not implemented'
91
94
  end
92
95
 
93
96
  # Entity Mapper Class
94
97
  def mapper_class
95
- raise "Not implemented"
98
+ raise 'Not implemented'
96
99
  end
97
100
 
98
101
  # An array of connec fields that are references
@@ -153,7 +156,7 @@ module Maestrano::Connector::Rails::Concerns::Entity
153
156
  def map_to_connec(entity)
154
157
  mapped_entity = self.class.mapper_class.denormalize(entity).merge(id: self.class.id_from_external_entity_hash(entity))
155
158
  folded_entity = Maestrano::Connector::Rails::ConnecHelper.fold_references(mapped_entity, self.class.references, @organization)
156
- folded_entity.merge!(opts: (mapped_entity[:opts] || {}).merge(matching_fields: self.class.connec_matching_fields)) if self.class.connec_matching_fields
159
+ folded_entity[:opts] = (mapped_entity[:opts] || {}).merge(matching_fields: self.class.connec_matching_fields) if self.class.connec_matching_fields
157
160
  folded_entity
158
161
  end
159
162
 
@@ -164,12 +167,11 @@ module Maestrano::Connector::Rails::Concerns::Entity
164
167
  # * full_sync
165
168
  # * $filter (see Connec! documentation)
166
169
  # * $orderby (see Connec! documentation)
167
- def get_connec_entities(last_synchronization_date=nil)
170
+ def get_connec_entities(last_synchronization_date = nil)
168
171
  return [] if @opts[:__skip_connec] || !self.class.can_read_connec?
169
172
 
170
173
  Maestrano::Connector::Rails::ConnectorLogger.log('info', @organization, "Fetching Connec! #{self.class.connec_entity_name}")
171
174
 
172
- entities = []
173
175
  query_params = {}
174
176
  query_params[:$orderby] = @opts[:$orderby] if @opts[:$orderby]
175
177
 
@@ -191,7 +193,7 @@ module Maestrano::Connector::Rails::Concerns::Entity
191
193
  Maestrano::Connector::Rails::ConnectorLogger.log('debug', @organization, "entity=#{self.class.connec_entity_name}, fetching data with #{query_params.to_query}")
192
194
  uri = "#{self.class.normalized_connec_entity_name}?#{query_params.to_query}"
193
195
  response_hash = fetch_connec(uri, 0)
194
- entities = response_hash["#{self.class.normalized_connec_entity_name}"]
196
+ entities = response_hash[self.class.normalized_connec_entity_name]
195
197
  entities = [entities] if self.class.singleton?
196
198
 
197
199
  # Only the first page if batched_fetch
@@ -203,7 +205,7 @@ module Maestrano::Connector::Rails::Concerns::Entity
203
205
  next_page = response_hash['pagination']['next'].gsub(/^(.*)\/#{self.class.normalized_connec_entity_name}/, self.class.normalized_connec_entity_name)
204
206
 
205
207
  response_hash = fetch_connec(next_page, page_number)
206
- entities << response_hash["#{self.class.normalized_connec_entity_name}"]
208
+ entities << response_hash[self.class.normalized_connec_entity_name]
207
209
  end
208
210
  end
209
211
 
@@ -220,8 +222,8 @@ module Maestrano::Connector::Rails::Concerns::Entity
220
222
  return unless self.class.can_write_connec?
221
223
 
222
224
  Maestrano::Connector::Rails::ConnectorLogger.log('info', @organization, "Sending #{Maestrano::Connector::Rails::External.external_name} #{self.class.external_entity_name.pluralize} to Connec! #{connec_entity_name.pluralize}")
223
-
224
- proc = lambda{|mapped_external_entity_with_idmap| batch_op('post', mapped_external_entity_with_idmap[:entity], nil, self.class.normalize_connec_entity_name(connec_entity_name))}
225
+
226
+ proc = ->(mapped_external_entity_with_idmap) { batch_op('post', mapped_external_entity_with_idmap[:entity], nil, self.class.normalize_connec_entity_name(connec_entity_name)) }
225
227
  batch_calls(mapped_external_entities_with_idmaps, proc, connec_entity_name)
226
228
  end
227
229
 
@@ -231,7 +233,7 @@ module Maestrano::Connector::Rails::Concerns::Entity
231
233
  method: method,
232
234
  url: "/api/v2/#{@organization.uid}/#{connec_entity_name}/#{id}", # id should be nil for POST
233
235
  params: {
234
- "#{connec_entity_name}".to_sym => mapped_external_entity
236
+ connec_entity_name.to_sym => mapped_external_entity
235
237
  }
236
238
  }
237
239
  end
@@ -239,14 +241,14 @@ module Maestrano::Connector::Rails::Concerns::Entity
239
241
  # ----------------------------------------------
240
242
  # External methods
241
243
  # ----------------------------------------------
242
- def get_external_entities_wrapper(last_synchronization_date=nil)
244
+ def get_external_entities_wrapper(last_synchronization_date = nil)
243
245
  return [] if @opts[:__skip_external] || !self.class.can_read_external?
244
246
  get_external_entities(last_synchronization_date)
245
247
  end
246
-
247
- def get_external_entities(last_synchronization_date=nil)
248
+
249
+ def get_external_entities(last_synchronization_date = nil)
248
250
  Maestrano::Connector::Rails::ConnectorLogger.log('info', @organization, "Fetching #{Maestrano::Connector::Rails::External.external_name} #{self.class.external_entity_name.pluralize}")
249
- raise "Not implemented"
251
+ raise 'Not implemented'
250
252
  end
251
253
 
252
254
  def push_entities_to_external(mapped_connec_entities_with_idmaps)
@@ -262,13 +264,12 @@ module Maestrano::Connector::Rails::Concerns::Entity
262
264
  idmap ? {idmap: idmap} : nil
263
265
  }.compact
264
266
 
265
- unless ids_to_send_to_connec.empty?
266
- # Send the external ids to connec if it was a creation
267
- proc = lambda{|id| batch_op('put', {id: [Maestrano::Connector::Rails::ConnecHelper.id_hash(id[:idmap].external_id, @organization)]}, id[:idmap].connec_id, self.class.normalize_connec_entity_name(self.class.connec_entity_name)) }
268
- batch_calls(ids_to_send_to_connec, proc, self.class.connec_entity_name, true)
269
- end
270
- end
267
+ return if ids_to_send_to_connec.empty?
271
268
 
269
+ # Send the external ids to connec if it was a creation
270
+ proc = ->(id) { batch_op('put', {id: [Maestrano::Connector::Rails::ConnecHelper.id_hash(id[:idmap].external_id, @organization)]}, id[:idmap].connec_id, self.class.normalize_connec_entity_name(self.class.connec_entity_name)) }
271
+ batch_calls(ids_to_send_to_connec, proc, self.class.connec_entity_name, true)
272
+ end
272
273
 
273
274
  def push_entity_to_external(mapped_connec_entity_with_idmap, external_entity_name)
274
275
  idmap = mapped_connec_entity_with_idmap[:idmap]
@@ -277,7 +278,6 @@ module Maestrano::Connector::Rails::Concerns::Entity
277
278
  begin
278
279
  # Create and return id to send to connec!
279
280
  if idmap.external_id.blank?
280
- connec_id = idmap.connec_id
281
281
  external_id = create_external_entity(mapped_connec_entity, external_entity_name)
282
282
  idmap.update(external_id: external_id, last_push_to_external: Time.now, message: nil)
283
283
  return idmap
@@ -289,13 +289,12 @@ module Maestrano::Connector::Rails::Concerns::Entity
289
289
 
290
290
  # Return the id to send it to connec! if the first push of a singleton
291
291
  if self.class.singleton? && idmap.last_push_to_external.nil?
292
- connec_id = mapped_connec_entity_with_idmap[:idmap].connec_id
293
292
  idmap.update(last_push_to_external: Time.now, message: nil)
294
293
  return idmap
295
294
  else
296
295
  idmap.update(last_push_to_external: Time.now, message: nil)
297
296
  end
298
-
297
+
299
298
  end
300
299
  rescue => e
301
300
  # Store External error
@@ -307,12 +306,12 @@ module Maestrano::Connector::Rails::Concerns::Entity
307
306
 
308
307
  def create_external_entity(mapped_connec_entity, external_entity_name)
309
308
  Maestrano::Connector::Rails::ConnectorLogger.log('info', @organization, "Sending create #{external_entity_name}: #{mapped_connec_entity} to #{Maestrano::Connector::Rails::External.external_name}")
310
- raise "Not implemented"
309
+ raise 'Not implemented'
311
310
  end
312
311
 
313
312
  def update_external_entity(mapped_connec_entity, external_id, external_entity_name)
314
313
  Maestrano::Connector::Rails::ConnectorLogger.log('info', @organization, "Sending update #{external_entity_name} (id=#{external_id}): #{mapped_connec_entity} to #{Maestrano::Connector::Rails::External.external_name}")
315
- raise "Not implemented"
314
+ raise 'Not implemented'
316
315
  end
317
316
 
318
317
  # ----------------------------------------------
@@ -329,7 +328,7 @@ module Maestrano::Connector::Rails::Concerns::Entity
329
328
  mapped_connec_entities = consolidate_and_map_connec_entities(connec_entities, external_entities, self.class.references, self.class.external_entity_name)
330
329
  mapped_external_entities = consolidate_and_map_external_entities(external_entities, self.class.connec_entity_name)
331
330
 
332
- return {connec_entities: mapped_connec_entities, external_entities: mapped_external_entities}
331
+ {connec_entities: mapped_connec_entities, external_entities: mapped_external_entities}
333
332
  end
334
333
 
335
334
  def consolidate_and_map_connec_entities(connec_entities, external_entities, references, external_entity_name)
@@ -374,7 +373,6 @@ module Maestrano::Connector::Rails::Concerns::Entity
374
373
  # Entity has not been modified since its last push to connec!
375
374
  next nil if !@opts[:full_sync] && not_modified_since_last_push_to_connec?(idmap, entity)
376
375
 
377
-
378
376
  map_external_entity_with_idmap(entity, connec_entity_name, idmap)
379
377
  }.compact
380
378
  end
@@ -382,18 +380,18 @@ module Maestrano::Connector::Rails::Concerns::Entity
382
380
  def consolidate_and_map_singleton(connec_entities, external_entities)
383
381
  return {connec_entities: [], external_entities: []} if external_entities.empty? && connec_entities.empty?
384
382
 
385
- idmap = self.class.find_or_create_idmap({organization_id: @organization.id})
383
+ idmap = self.class.find_or_create_idmap(organization_id: @organization.id)
386
384
  # No to_connec, to_external and inactive consideration here as we don't expect those workflow for singleton
387
385
 
388
- if external_entities.empty?
389
- keep_external = false
390
- elsif connec_entities.empty?
391
- keep_external = true
392
- elsif @opts.has_key?(:connec_preemption)
393
- keep_external = !@opts[:connec_preemption]
394
- else
395
- keep_external = !is_connec_more_recent?(connec_entities.first, external_entities.first)
396
- end
386
+ keep_external = if external_entities.empty?
387
+ false
388
+ elsif connec_entities.empty?
389
+ true
390
+ elsif @opts.key?(:connec_preemption)
391
+ !@opts[:connec_preemption]
392
+ else
393
+ !is_connec_more_recent?(connec_entities.first, external_entities.first)
394
+ end
397
395
 
398
396
  if keep_external
399
397
  idmap.update(external_id: self.class.id_from_external_entity_hash(external_entities.first), name: self.class.object_name_from_external_entity_hash(external_entities.first))
@@ -410,9 +408,10 @@ module Maestrano::Connector::Rails::Concerns::Entity
410
408
  # Internal helper methods
411
409
  # ----------------------------------------------
412
410
  private
411
+
413
412
  # array_with_idmap must be an array of hashes with a key idmap
414
413
  # proc is a lambda to create a batch_op from an element of the array
415
- def batch_calls(array_with_idmap, proc, connec_entity_name, id_update_only=false)
414
+ def batch_calls(array_with_idmap, proc, connec_entity_name, id_update_only = false)
416
415
  request_per_call = @opts[:request_per_batch_call] || 100
417
416
  start = 0
418
417
  while start < array_with_idmap.size
@@ -426,7 +425,7 @@ module Maestrano::Connector::Rails::Concerns::Entity
426
425
 
427
426
  # Batch call
428
427
  log_info = id_update_only ? 'with only ids' : ''
429
- Maestrano::Connector::Rails::ConnectorLogger.log('info', @organization, "Sending batch request to Connec! #{log_info} for #{self.class.normalize_connec_entity_name(connec_entity_name)}. Batch_request_size: #{batch_request[:ops].size}. Call_number: #{(start/request_per_call) + 1}")
428
+ Maestrano::Connector::Rails::ConnectorLogger.log('info', @organization, "Sending batch request to Connec! #{log_info} for #{self.class.normalize_connec_entity_name(connec_entity_name)}. Batch_request_size: #{batch_request[:ops].size}. Call_number: #{(start / request_per_call) + 1}")
430
429
  response = @connec_client.batch(batch_request)
431
430
  Maestrano::Connector::Rails::ConnectorLogger.log('debug', @organization, "Received batch response from Connec! for #{self.class.normalize_connec_entity_name(connec_entity_name)}: #{response}")
432
431
  raise "No data received from Connec! when trying to send batch request #{log_info} for #{self.class.connec_entity_name.pluralize}" unless response && !response.body.blank?
@@ -435,9 +434,9 @@ module Maestrano::Connector::Rails::Concerns::Entity
435
434
  # Parse batch response
436
435
  response['results'].each_with_index do |result, index|
437
436
  if result['status'] == 200
438
- batch_entities[index][:idmap].update(connec_id: result['body'][self.class.normalize_connec_entity_name(connec_entity_name)]['id'].find{|id| id['provider'] == 'connec'}['id'], last_push_to_connec: Time.now, message: nil) unless id_update_only # id_update_only only apply for 200 as it's doing PUTs
437
+ batch_entities[index][:idmap].update(connec_id: result['body'][self.class.normalize_connec_entity_name(connec_entity_name)]['id'].find { |id| id['provider'] == 'connec' }['id'], last_push_to_connec: Time.now, message: nil) unless id_update_only # id_update_only only apply for 200 as it's doing PUTs
439
438
  elsif result['status'] == 201
440
- batch_entities[index][:idmap].update(connec_id: result['body'][self.class.normalize_connec_entity_name(connec_entity_name)]['id'].find{|id| id['provider'] == 'connec'}['id'], last_push_to_connec: Time.now, message: nil)
439
+ batch_entities[index][:idmap].update(connec_id: result['body'][self.class.normalize_connec_entity_name(connec_entity_name)]['id'].find { |id| id['provider'] == 'connec' }['id'], last_push_to_connec: Time.now, message: nil)
441
440
  else
442
441
  Maestrano::Connector::Rails::ConnectorLogger.log('error', @organization, "Error while pushing to Connec!: #{result['body']}")
443
442
  batch_entities[index][:idmap].update(message: result['body'].to_s.truncate(255))
@@ -446,10 +445,10 @@ module Maestrano::Connector::Rails::Concerns::Entity
446
445
  start += request_per_call
447
446
  end
448
447
  end
449
-
448
+
450
449
  def not_modified_since_last_push_to_connec?(idmap, entity)
451
450
  not_modified = idmap.last_push_to_connec && idmap.last_push_to_connec > self.class.last_update_date_from_external_entity_hash(entity)
452
- Maestrano::Connector::Rails::ConnectorLogger.log('info', @organization, "Discard #{Maestrano::Connector::Rails::External::external_name} #{self.class.external_entity_name} : #{entity}") if not_modified
451
+ Maestrano::Connector::Rails::ConnectorLogger.log('info', @organization, "Discard #{Maestrano::Connector::Rails::External.external_name} #{self.class.external_entity_name} : #{entity}") if not_modified
453
452
  not_modified
454
453
  end
455
454
 
@@ -459,7 +458,7 @@ module Maestrano::Connector::Rails::Concerns::Entity
459
458
  not_modified
460
459
  end
461
460
 
462
- def before_date_filtering_limit?(entity, external=true)
461
+ def before_date_filtering_limit?(entity, external = true)
463
462
  @organization.date_filtering_limit && @organization.date_filtering_limit > (external ? self.class.creation_date_from_external_entity_hash(entity) : entity['created_at'])
464
463
  end
465
464
 
@@ -468,25 +467,21 @@ module Maestrano::Connector::Rails::Concerns::Entity
468
467
  end
469
468
 
470
469
  def solve_conflict(connec_entity, external_entities, external_entity_name, idmap)
471
- if external_entity = external_entities.find{|external_entity| connec_entity['id'] == self.class.id_from_external_entity_hash(external_entity)}
472
- # We keep the most recently updated entity
473
- if @opts.has_key?(:connec_preemption)
474
- keep_connec = @opts[:connec_preemption]
475
- else
476
- keep_connec = is_connec_more_recent?(connec_entity, external_entity)
477
- end
470
+ external_entity = external_entities.find { |entity| connec_entity['id'] == self.class.id_from_external_entity_hash(entity) }
471
+ # No conflict
472
+ return map_connec_entity_with_idmap(connec_entity, external_entity_name, idmap) unless external_entity
478
473
 
479
- if keep_connec
480
- Maestrano::Connector::Rails::ConnectorLogger.log('info', @organization, "Conflict between #{Maestrano::Connector::Rails::External::external_name} #{external_entity_name} #{external_entity} and Connec! #{self.class.connec_entity_name} #{connec_entity}. Entity from Connec! kept")
481
- external_entities.delete(external_entity)
482
- map_connec_entity_with_idmap(connec_entity, external_entity_name, idmap)
483
- else
484
- Maestrano::Connector::Rails::ConnectorLogger.log('info', @organization, "Conflict between #{Maestrano::Connector::Rails::External::external_name} #{external_entity_name} #{external_entity} and Connec! #{self.class.connec_entity_name} #{connec_entity}. Entity from external kept")
485
- nil
486
- end
474
+ # Conflict
475
+ # We keep the most recently updated entity
476
+ keep_connec = @opts.key?(:connec_preemption) ? @opts[:connec_preemption] : is_connec_more_recent?(connec_entity, external_entity)
487
477
 
488
- else
478
+ if keep_connec
479
+ Maestrano::Connector::Rails::ConnectorLogger.log('info', @organization, "Conflict between #{Maestrano::Connector::Rails::External.external_name} #{external_entity_name} #{external_entity} and Connec! #{self.class.connec_entity_name} #{connec_entity}. Entity from Connec! kept")
480
+ external_entities.delete(external_entity)
489
481
  map_connec_entity_with_idmap(connec_entity, external_entity_name, idmap)
482
+ else
483
+ Maestrano::Connector::Rails::ConnectorLogger.log('info', @organization, "Conflict between #{Maestrano::Connector::Rails::External.external_name} #{external_entity_name} #{external_entity} and Connec! #{self.class.connec_entity_name} #{connec_entity}. Entity from external kept")
484
+ nil
490
485
  end
491
486
  end
492
487
 
@@ -504,9 +499,8 @@ module Maestrano::Connector::Rails::Concerns::Entity
504
499
 
505
500
  response_hash = JSON.parse(response.body)
506
501
  Maestrano::Connector::Rails::ConnectorLogger.log('debug', @organization, "Received page #{page_number} for entity=#{self.class.connec_entity_name}, response=#{response_hash}")
507
- raise "Received unrecognized Connec! data when trying to fetch page #{page_number} of #{self.class.normalized_connec_entity_name}: #{response_hash}" unless response_hash["#{self.class.normalized_connec_entity_name}"]
502
+ raise "Received unrecognized Connec! data when trying to fetch page #{page_number} of #{self.class.normalized_connec_entity_name}: #{response_hash}" unless response_hash[self.class.normalized_connec_entity_name]
508
503
 
509
504
  response_hash
510
505
  end
511
-
512
- end
506
+ end