maestrano-connector-rails 0.2.16 → 0.2.17
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +3 -0
- data/Gemfile.lock +27 -0
- data/VERSION +1 -1
- data/app/helpers/maestrano/connector/rails/session_helper.rb +5 -1
- data/app/models/maestrano/connector/rails/complex_entity.rb +14 -33
- data/app/models/maestrano/connector/rails/concerns/entity.rb +161 -73
- data/app/models/maestrano/connector/rails/sub_entity_base.rb +44 -4
- data/lib/generators/connector/install_generator.rb +20 -24
- data/lib/generators/connector/templates/home_controller.rb +33 -10
- data/lib/generators/connector/templates/home_controller_spec.rb +141 -0
- data/lib/generators/connector/templates/home_index.haml +103 -0
- data/lib/generators/connector/templates/layouts.haml +45 -0
- data/lib/generators/connector/templates/oauth_controller.rb +3 -6
- data/lib/generators/connector/templates/shared_entities_controller.rb +7 -0
- data/lib/generators/connector/templates/shared_entities_controller_spec.rb +23 -0
- data/lib/generators/connector/templates/shared_entities_index.haml +41 -0
- data/lib/generators/connector/templates/stylesheets/application.sass +24 -0
- data/lib/generators/connector/templates/stylesheets/banners.sass +59 -0
- data/lib/generators/connector/templates/stylesheets/home.sass +25 -0
- data/lib/generators/connector/templates/stylesheets/layout.sass +125 -0
- data/lib/generators/connector/templates/stylesheets/spacers.sass +46 -0
- data/lib/generators/connector/templates/stylesheets/variables.sass +57 -0
- data/lib/generators/connector/templates/sychronizations_controller_spec.rb +22 -0
- data/lib/generators/connector/templates/synchronizations_controller.rb +7 -0
- data/lib/generators/connector/templates/synchronizations_index.haml +42 -0
- data/maestrano-connector-rails.gemspec +29 -6
- data/pkg/maestrano-connector-rails-0.2.16.gem +0 -0
- data/spec/models/complex_entity_spec.rb +46 -12
- data/spec/models/entity_spec.rb +212 -113
- data/spec/models/sub_entity_base_spec.rb +59 -0
- data/template/maestrano-connector-template.rb +4 -3
- data/template/routes.rb +14 -0
- metadata +61 -5
- data/lib/generators/connector/templates/admin_controller.rb +0 -58
- data/lib/generators/connector/templates/admin_index.html.erb +0 -55
- data/lib/generators/connector/templates/home_index.html.erb +0 -48
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fb5c07cb2cd6e41eed0cf6d969bccfaca04bbfd7
|
4
|
+
data.tar.gz: 597eff9e10f8091d32df3efa8fe3d401686471b1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8255bd1676f26950267b98125e88679f3d91d5d127e650fbcfe4bc7d72c55b4d3d5ef3742022b6e2cdd267d5cab9d0fa449ed4197817f94c8ee43400320c4a55
|
7
|
+
data.tar.gz: 897a96ac9045cb71828ade21e216586f34db7af9bbec6ea7d6c1dca7cdbcbf9666e44a4a5dcb8f1fdb74fcd2fa194fa6f8386125f49b8cc21c73fc4dc372a65c
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -38,6 +38,11 @@ GEM
|
|
38
38
|
tzinfo (~> 1.1)
|
39
39
|
addressable (2.4.0)
|
40
40
|
arel (6.0.3)
|
41
|
+
autoprefixer-rails (6.3.3.1)
|
42
|
+
execjs
|
43
|
+
bootstrap-sass (3.3.6)
|
44
|
+
autoprefixer-rails (>= 5.2.1)
|
45
|
+
sass (>= 3.3.4)
|
41
46
|
builder (3.2.2)
|
42
47
|
concurrent-ruby (1.0.0)
|
43
48
|
connection_pool (2.2.0)
|
@@ -48,6 +53,7 @@ GEM
|
|
48
53
|
domain_name (0.5.20160128)
|
49
54
|
unf (>= 0.0.5, < 1.0.0)
|
50
55
|
erubis (2.7.0)
|
56
|
+
execjs (2.6.0)
|
51
57
|
factory_girl (4.5.0)
|
52
58
|
activesupport (>= 3.0.0)
|
53
59
|
factory_girl_rails (4.6.0)
|
@@ -65,10 +71,23 @@ GEM
|
|
65
71
|
oauth2
|
66
72
|
globalid (0.3.6)
|
67
73
|
activesupport (>= 4.1.0)
|
74
|
+
haml (4.0.7)
|
75
|
+
tilt
|
76
|
+
haml-rails (0.9.0)
|
77
|
+
actionpack (>= 4.0.1)
|
78
|
+
activesupport (>= 4.0.1)
|
79
|
+
haml (>= 4.0.6, < 5.0)
|
80
|
+
html2haml (>= 1.0.1)
|
81
|
+
railties (>= 4.0.1)
|
68
82
|
hash_mapper (0.2.1)
|
69
83
|
activesupport (~> 4)
|
70
84
|
hashie (3.4.3)
|
71
85
|
highline (1.7.8)
|
86
|
+
html2haml (2.0.0)
|
87
|
+
erubis (~> 2.7.0)
|
88
|
+
haml (~> 4.0.0)
|
89
|
+
nokogiri (~> 1.6.0)
|
90
|
+
ruby_parser (~> 3.5)
|
72
91
|
http-cookie (1.0.2)
|
73
92
|
domain_name (~> 0.5)
|
74
93
|
httparty (0.13.7)
|
@@ -174,6 +193,10 @@ GEM
|
|
174
193
|
rspec-mocks (~> 3.4.0)
|
175
194
|
rspec-support (~> 3.4.0)
|
176
195
|
rspec-support (3.4.1)
|
196
|
+
ruby_parser (3.8.1)
|
197
|
+
sexp_processor (~> 4.1)
|
198
|
+
sass (3.4.21)
|
199
|
+
sexp_processor (4.7.0)
|
177
200
|
shoulda (3.5.0)
|
178
201
|
shoulda-context (~> 1.0, >= 1.0.1)
|
179
202
|
shoulda-matchers (>= 1.4.1, < 3.0)
|
@@ -200,6 +223,7 @@ GEM
|
|
200
223
|
systemu (2.6.5)
|
201
224
|
thor (0.19.1)
|
202
225
|
thread_safe (0.3.5)
|
226
|
+
tilt (2.0.2)
|
203
227
|
tzinfo (1.2.2)
|
204
228
|
thread_safe (~> 0.1)
|
205
229
|
unf (0.1.4)
|
@@ -212,8 +236,11 @@ PLATFORMS
|
|
212
236
|
ruby
|
213
237
|
|
214
238
|
DEPENDENCIES
|
239
|
+
autoprefixer-rails
|
240
|
+
bootstrap-sass
|
215
241
|
bundler (~> 1.0)
|
216
242
|
factory_girl_rails
|
243
|
+
haml-rails
|
217
244
|
hash_mapper
|
218
245
|
jeweler (~> 2.0.1)
|
219
246
|
maestrano-rails
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.17
|
@@ -6,12 +6,16 @@ module Maestrano::Connector::Rails
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def current_organization
|
9
|
-
Organization.find_by(uid: session[:org_uid], tenant: session[:tenant])
|
9
|
+
@current_organization ||= Organization.find_by(uid: session[:org_uid], tenant: session[:tenant])
|
10
10
|
end
|
11
11
|
|
12
12
|
def current_user
|
13
13
|
@current_user ||= User.find_by(uid: session[:uid], tenant: session[:tenant])
|
14
14
|
end
|
15
15
|
|
16
|
+
def is_admin
|
17
|
+
@is_admin ||= current_user && current_organization && is_admin?(current_user, current_organization)
|
18
|
+
end
|
19
|
+
|
16
20
|
end
|
17
21
|
end
|
@@ -52,14 +52,14 @@ module Maestrano::Connector::Rails
|
|
52
52
|
# -------------------------------------------------------------
|
53
53
|
# General methods
|
54
54
|
# -------------------------------------------------------------
|
55
|
-
def map_to_external_with_idmap(entity, organization,
|
56
|
-
idmap =
|
55
|
+
def map_to_external_with_idmap(entity, organization, external_entity_name, sub_entity_instance)
|
56
|
+
idmap = sub_entity_instance.find_idmap({connec_id: entity['id'], external_entity: external_entity_name, organization_id: organization.id})
|
57
57
|
|
58
|
-
if idmap && idmap.last_push_to_external && idmap.last_push_to_external > entity['updated_at']
|
59
|
-
ConnectorLogger.log('info', organization, "Discard Connec! #{
|
58
|
+
if idmap && ((!idmap.to_external) || idmap.last_push_to_external && idmap.last_push_to_external > entity['updated_at'])
|
59
|
+
ConnectorLogger.log('info', organization, "Discard Connec! #{sub_entity_instance.entity_name} : #{entity}")
|
60
60
|
nil
|
61
61
|
else
|
62
|
-
{entity: sub_entity_instance.map_to(external_entity_name, entity, organization), idmap: idmap ||
|
62
|
+
{entity: sub_entity_instance.map_to(external_entity_name, entity, organization), idmap: idmap || sub_entity_instance.create_idmap_from_connec_entity(entity, external_entity_name, organization)}
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
@@ -95,41 +95,22 @@ module Maestrano::Connector::Rails
|
|
95
95
|
sub_entity_instance = "Entities::SubEntities::#{external_entity_name.titleize.split.join}".constantize.new
|
96
96
|
|
97
97
|
entities.map!{|entity|
|
98
|
-
idmap =
|
98
|
+
idmap = sub_entity_instance.find_idmap(external_id: sub_entity_instance.get_id_from_external_entity_hash(entity), connec_entity: connec_entity_name, organization_id: organization.id)
|
99
99
|
|
100
100
|
# No idmap: creating one, nothing else to do
|
101
101
|
unless idmap
|
102
|
-
next {entity: sub_entity_instance.map_to(connec_entity_name, entity, organization), idmap:
|
102
|
+
next {entity: sub_entity_instance.map_to(connec_entity_name, entity, organization), idmap: sub_entity_instance.create_idmap_from_external_entity(entity, connec_entity_name, organization)}
|
103
103
|
end
|
104
104
|
|
105
|
+
# Not pushing entity to Connec!
|
106
|
+
next nil unless idmap.to_connec
|
107
|
+
|
105
108
|
# Entity has not been modified since its last push to connec!
|
106
|
-
if
|
107
|
-
ConnectorLogger.log('info', organization, "Discard #{@@external_name} #{external_entity_name} : #{entity}")
|
108
|
-
next nil
|
109
|
-
end
|
109
|
+
next nil if Maestrano::Connector::Rails::Entity.not_modified_since_last_push_to_connec(idmap, entity, sub_entity_instance, organization)
|
110
110
|
|
111
|
-
equivalent_connec_entities = connec_entities[connec_entity_name][external_entity_name] || []
|
112
111
|
# Check for conflict with entities from connec!
|
113
|
-
|
114
|
-
|
115
|
-
if !opts[:connec_preemption].nil?
|
116
|
-
keep_external = !opts[:connec_preemption]
|
117
|
-
else
|
118
|
-
keep_external = connec_entity['updated_at'] < sub_entity_instance.get_last_update_date_from_external_entity_hash(entity)
|
119
|
-
end
|
120
|
-
|
121
|
-
if keep_external
|
122
|
-
ConnectorLogger.log('info', organization, "Conflict between #{@@external_name} #{external_entity_name} #{entity} and Connec! #{connec_entity_name} #{connec_entity}. Entity from #{@@external_name} kept")
|
123
|
-
equivalent_connec_entities.delete(connec_entity)
|
124
|
-
{entity: sub_entity_instance.map_to(connec_entity_name, entity, organization), idmap: idmap}
|
125
|
-
else
|
126
|
-
ConnectorLogger.log('info', organization, "Conflict between #{@@external_name} #{external_entity_name} #{entity} and Connec! #{connec_entity_name} #{connec_entity}. Entity from Connec! kept")
|
127
|
-
nil
|
128
|
-
end
|
129
|
-
|
130
|
-
else
|
131
|
-
{entity: sub_entity_instance.map_to(connec_entity_name, entity, organization), idmap: idmap}
|
132
|
-
end
|
112
|
+
equivalent_connec_entities = modeled_connec_entities[connec_entity_name][external_entity_name] || []
|
113
|
+
Maestrano::Connector::Rails::Entity.solve_conflict(entity, sub_entity_instance, equivalent_connec_entities, connec_entity_name, idmap, organization, opts)
|
133
114
|
}.compact!
|
134
115
|
end
|
135
116
|
end
|
@@ -138,7 +119,7 @@ module Maestrano::Connector::Rails
|
|
138
119
|
entities_in_external_model.each do |external_entity_name, entities|
|
139
120
|
sub_entity_instance = "Entities::SubEntities::#{connec_entity_name.titleize.split.join}".constantize.new
|
140
121
|
entities.map!{|entity|
|
141
|
-
self.map_to_external_with_idmap(entity, organization,
|
122
|
+
self.map_to_external_with_idmap(entity, organization, external_entity_name, sub_entity_instance)
|
142
123
|
}.compact!
|
143
124
|
end
|
144
125
|
end
|
@@ -17,116 +17,159 @@ module Maestrano::Connector::Rails::Concerns::Entity
|
|
17
17
|
# ----------------------------------------------
|
18
18
|
# Map a Connec! entity to the external format
|
19
19
|
def map_to_external(entity, organization)
|
20
|
-
|
20
|
+
mapper_class.normalize(entity)
|
21
21
|
end
|
22
22
|
|
23
23
|
# Map an external entity to Connec! format
|
24
24
|
def map_to_connec(entity, organization)
|
25
|
-
|
25
|
+
mapper_class.denormalize(entity)
|
26
26
|
end
|
27
27
|
|
28
|
+
# ----------------------------------------------
|
29
|
+
# IdMap methods
|
30
|
+
# ----------------------------------------------
|
31
|
+
def names_hash
|
32
|
+
{
|
33
|
+
connec_entity: connec_entity_name.downcase,
|
34
|
+
external_entity: external_entity_name.downcase
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
def find_or_create_idmap(organization_and_id)
|
39
|
+
Maestrano::Connector::Rails::IdMap.find_or_create_by(names_hash.merge(organization_and_id))
|
40
|
+
end
|
41
|
+
|
42
|
+
# organization_and_id can be either:
|
43
|
+
# * {connec_id: 'id', organization_id: 'id'}
|
44
|
+
# * {external_id: 'id', organization_id: 'id'}
|
45
|
+
# Needs to include either connec_entity or external_entity for complex entities
|
46
|
+
def find_idmap(organization_and_id)
|
47
|
+
Maestrano::Connector::Rails::IdMap.find_by(names_hash.merge(organization_and_id))
|
48
|
+
end
|
49
|
+
|
50
|
+
def create_idmap_from_external_entity(entity, organization)
|
51
|
+
h = names_hash.merge({
|
52
|
+
external_id: get_id_from_external_entity_hash(entity),
|
53
|
+
name: object_name_from_external_entity_hash(entity),
|
54
|
+
organization_id: organization.id
|
55
|
+
})
|
56
|
+
Maestrano::Connector::Rails::IdMap.create(h)
|
57
|
+
end
|
58
|
+
|
59
|
+
def create_idmap_from_connec_entity(entity, organization)
|
60
|
+
h = names_hash.merge({
|
61
|
+
connec_id: entity['id'],
|
62
|
+
name: object_name_from_connec_entity_hash(entity),
|
63
|
+
organization_id: organization.id
|
64
|
+
})
|
65
|
+
Maestrano::Connector::Rails::IdMap.create(h)
|
66
|
+
end
|
28
67
|
# ----------------------------------------------
|
29
68
|
# Connec! methods
|
30
69
|
# ----------------------------------------------
|
31
70
|
def normalized_connec_entity_name
|
32
|
-
if
|
33
|
-
|
71
|
+
if singleton?
|
72
|
+
connec_entity_name.downcase
|
34
73
|
else
|
35
|
-
|
74
|
+
connec_entity_name.downcase.pluralize
|
36
75
|
end
|
37
76
|
end
|
38
77
|
|
39
78
|
def get_connec_entities(client, last_synchronization, organization, opts={})
|
40
|
-
Maestrano::Connector::Rails::ConnectorLogger.log('info', organization, "Fetching Connec! #{
|
79
|
+
Maestrano::Connector::Rails::ConnectorLogger.log('info', organization, "Fetching Connec! #{connec_entity_name}")
|
41
80
|
|
42
81
|
entities = []
|
43
82
|
|
44
83
|
# Fetch first page
|
45
84
|
if last_synchronization.blank? || opts[:full_sync]
|
46
|
-
Maestrano::Connector::Rails::ConnectorLogger.log('debug', organization, "entity=#{
|
47
|
-
response = client.get("/#{
|
85
|
+
Maestrano::Connector::Rails::ConnectorLogger.log('debug', organization, "entity=#{connec_entity_name}, fetching all data")
|
86
|
+
response = client.get("/#{normalized_connec_entity_name}")
|
48
87
|
else
|
49
|
-
Maestrano::Connector::Rails::ConnectorLogger.log('debug', organization, "entity=#{
|
88
|
+
Maestrano::Connector::Rails::ConnectorLogger.log('debug', organization, "entity=#{connec_entity_name}, fetching data since #{last_synchronization.updated_at.iso8601}")
|
50
89
|
query_param = URI.encode("$filter=updated_at gt '#{last_synchronization.updated_at.iso8601}'")
|
51
|
-
response = client.get("/#{
|
90
|
+
response = client.get("/#{normalized_connec_entity_name}?#{query_param}")
|
52
91
|
end
|
53
|
-
raise "No data received from Connec! when trying to fetch #{
|
92
|
+
raise "No data received from Connec! when trying to fetch #{connec_entity_name.pluralize}" unless response
|
54
93
|
|
55
94
|
response_hash = JSON.parse(response.body)
|
56
|
-
Maestrano::Connector::Rails::ConnectorLogger.log('debug', organization, "received first page entity=#{
|
57
|
-
if response_hash["#{
|
58
|
-
entities << response_hash["#{
|
95
|
+
Maestrano::Connector::Rails::ConnectorLogger.log('debug', organization, "received first page entity=#{connec_entity_name}, response=#{response.body}")
|
96
|
+
if response_hash["#{normalized_connec_entity_name}"]
|
97
|
+
entities << response_hash["#{normalized_connec_entity_name}"]
|
59
98
|
else
|
60
|
-
raise "Received unrecognized Connec! data when trying to fetch #{
|
99
|
+
raise "Received unrecognized Connec! data when trying to fetch #{connec_entity_name.pluralize}"
|
61
100
|
end
|
62
101
|
|
63
102
|
# Fetch subsequent pages
|
64
103
|
while response_hash['pagination'] && response_hash['pagination']['next']
|
65
104
|
# ugly way to convert https://api-connec/api/v2/group_id/organizations?next_page_params to /organizations?next_page_params
|
66
|
-
next_page = response_hash['pagination']['next'].gsub(/^(.*)\/#{
|
105
|
+
next_page = response_hash['pagination']['next'].gsub(/^(.*)\/#{normalized_connec_entity_name}/, normalized_connec_entity_name)
|
67
106
|
response = client.get(next_page)
|
68
107
|
|
69
|
-
raise "No data received from Connec! when trying to fetch subsequent page of #{
|
70
|
-
Maestrano::Connector::Rails::ConnectorLogger.log('debug', organization, "received next page entity=#{
|
108
|
+
raise "No data received from Connec! when trying to fetch subsequent page of #{connec_entity_name.pluralize}" unless response
|
109
|
+
Maestrano::Connector::Rails::ConnectorLogger.log('debug', organization, "received next page entity=#{connec_entity_name}, response=#{response.body}")
|
71
110
|
|
72
111
|
response_hash = JSON.parse(response.body)
|
73
|
-
if response_hash["#{
|
74
|
-
entities << response_hash["#{
|
112
|
+
if response_hash["#{normalized_connec_entity_name}"]
|
113
|
+
entities << response_hash["#{normalized_connec_entity_name}"]
|
75
114
|
else
|
76
|
-
raise "Received unrecognized Connec! data when trying to fetch subsequent page of #{
|
115
|
+
raise "Received unrecognized Connec! data when trying to fetch subsequent page of #{connec_entity_name.pluralize}"
|
77
116
|
end
|
78
117
|
end
|
79
118
|
|
80
119
|
entities = entities.flatten
|
81
|
-
Maestrano::Connector::Rails::ConnectorLogger.log('info', organization, "Received data: Source=Connec!, Entity=#{
|
120
|
+
Maestrano::Connector::Rails::ConnectorLogger.log('info', organization, "Received data: Source=Connec!, Entity=#{connec_entity_name}, Data=#{entities}")
|
82
121
|
entities
|
83
122
|
end
|
84
123
|
|
85
124
|
def push_entities_to_connec(connec_client, mapped_external_entities_with_idmaps, organization)
|
86
|
-
|
125
|
+
push_entities_to_connec_to(connec_client, mapped_external_entities_with_idmaps, connec_entity_name, organization)
|
87
126
|
end
|
88
127
|
|
89
128
|
def push_entities_to_connec_to(connec_client, mapped_external_entities_with_idmaps, connec_entity_name, organization)
|
90
|
-
Maestrano::Connector::Rails::ConnectorLogger.log('info', organization, "Sending #{@@external_name} #{
|
129
|
+
Maestrano::Connector::Rails::ConnectorLogger.log('info', organization, "Sending #{@@external_name} #{external_entity_name.pluralize} to Connec! #{connec_entity_name.pluralize}")
|
91
130
|
mapped_external_entities_with_idmaps.each do |mapped_external_entity_with_idmap|
|
92
131
|
external_entity = mapped_external_entity_with_idmap[:entity]
|
93
132
|
idmap = mapped_external_entity_with_idmap[:idmap]
|
94
133
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
134
|
+
begin
|
135
|
+
if idmap.connec_id.blank?
|
136
|
+
connec_entity = create_connec_entity(connec_client, external_entity, connec_entity_name, organization)
|
137
|
+
idmap.update_attributes(connec_id: connec_entity['id'], connec_entity: connec_entity_name.downcase, last_push_to_connec: Time.now, message: nil)
|
138
|
+
else
|
139
|
+
connec_entity = update_connec_entity(connec_client, external_entity, idmap.connec_id, connec_entity_name, organization)
|
140
|
+
idmap.update_attributes(last_push_to_connec: Time.now, message: nil)
|
141
|
+
end
|
142
|
+
rescue => e
|
143
|
+
# Store Connec! error if any
|
144
|
+
idmap.update_attributes(message: e.message)
|
101
145
|
end
|
102
|
-
|
103
|
-
# Store Connec! error if any
|
104
|
-
idmap.update_attributes(message: connec_entity['errors'].first['title']) unless connec_entity.blank? || connec_entity['errors'].blank?
|
105
146
|
end
|
106
147
|
end
|
107
148
|
|
108
149
|
def create_connec_entity(connec_client, mapped_external_entity, connec_entity_name, organization)
|
109
150
|
Maestrano::Connector::Rails::ConnectorLogger.log('info', organization, "Sending create #{connec_entity_name}: #{mapped_external_entity} to Connec!")
|
110
151
|
response = connec_client.post("/#{normalized_connec_entity_name}", { "#{normalized_connec_entity_name}".to_sym => mapped_external_entity })
|
111
|
-
|
112
|
-
|
152
|
+
response = JSON.parse(response.body)
|
153
|
+
raise "Connec!: #{response['errors']['title']}" if response['errors'] && response['errors']['title']
|
154
|
+
response["#{normalized_connec_entity_name}"]
|
113
155
|
end
|
114
156
|
|
115
157
|
def update_connec_entity(connec_client, mapped_external_entity, connec_id, connec_entity_name, organization)
|
116
158
|
Maestrano::Connector::Rails::ConnectorLogger.log('info', organization, "Sending update #{connec_entity_name}: #{mapped_external_entity} to Connec!")
|
117
159
|
response = connec_client.put("/#{normalized_connec_entity_name}/#{connec_id}", { "#{normalized_connec_entity_name}".to_sym => mapped_external_entity })
|
118
|
-
|
119
|
-
|
160
|
+
response = JSON.parse(response.body)
|
161
|
+
raise "Connec!: #{response['errors']['title']}" if response['errors'] && response['errors']['title']
|
162
|
+
response["#{normalized_connec_entity_name}"]
|
120
163
|
end
|
121
164
|
|
122
165
|
def map_to_external_with_idmap(entity, organization)
|
123
|
-
idmap =
|
166
|
+
idmap = find_idmap({connec_id: entity['id'], organization_id: organization.id})
|
124
167
|
|
125
168
|
if idmap && ((!idmap.to_external) || (idmap.last_push_to_external && idmap.last_push_to_external > entity['updated_at']))
|
126
|
-
Maestrano::Connector::Rails::ConnectorLogger.log('info', organization, "Discard Connec! #{
|
169
|
+
Maestrano::Connector::Rails::ConnectorLogger.log('info', organization, "Discard Connec! #{connec_entity_name} : #{entity}")
|
127
170
|
nil
|
128
171
|
else
|
129
|
-
{entity:
|
172
|
+
{entity: map_to_external(entity, organization), idmap: idmap || create_idmap_from_connec_entity(entity, organization)}
|
130
173
|
end
|
131
174
|
end
|
132
175
|
|
@@ -134,18 +177,18 @@ module Maestrano::Connector::Rails::Concerns::Entity
|
|
134
177
|
# External methods
|
135
178
|
# ----------------------------------------------
|
136
179
|
def get_external_entities(client, last_synchronization, organization, opts={})
|
137
|
-
Maestrano::Connector::Rails::ConnectorLogger.log('info', organization, "Fetching #{@@external_name} #{
|
180
|
+
Maestrano::Connector::Rails::ConnectorLogger.log('info', organization, "Fetching #{@@external_name} #{external_entity_name.pluralize}")
|
138
181
|
raise "Not implemented"
|
139
182
|
end
|
140
183
|
|
141
184
|
def push_entities_to_external(external_client, mapped_connec_entities_with_idmaps, organization)
|
142
|
-
push_entities_to_external_to(external_client, mapped_connec_entities_with_idmaps,
|
185
|
+
push_entities_to_external_to(external_client, mapped_connec_entities_with_idmaps, external_entity_name, organization)
|
143
186
|
end
|
144
187
|
|
145
188
|
def push_entities_to_external_to(external_client, mapped_connec_entities_with_idmaps, external_entity_name, organization)
|
146
|
-
Maestrano::Connector::Rails::ConnectorLogger.log('info', organization, "Sending Connec! #{
|
189
|
+
Maestrano::Connector::Rails::ConnectorLogger.log('info', organization, "Sending Connec! #{connec_entity_name.pluralize} to #{@@external_name} #{external_entity_name.pluralize}")
|
147
190
|
mapped_connec_entities_with_idmaps.each do |mapped_connec_entity_with_idmap|
|
148
|
-
|
191
|
+
push_entity_to_external(external_client, mapped_connec_entity_with_idmap, external_entity_name, organization)
|
149
192
|
end
|
150
193
|
end
|
151
194
|
|
@@ -155,10 +198,10 @@ module Maestrano::Connector::Rails::Concerns::Entity
|
|
155
198
|
|
156
199
|
begin
|
157
200
|
if idmap.external_id.blank?
|
158
|
-
external_id =
|
201
|
+
external_id = create_external_entity(external_client, connec_entity, external_entity_name, organization)
|
159
202
|
idmap.update_attributes(external_id: external_id, external_entity: external_entity_name.downcase, last_push_to_external: Time.now, message: nil)
|
160
203
|
else
|
161
|
-
|
204
|
+
update_external_entity(external_client, connec_entity, idmap.external_id, external_entity_name, organization)
|
162
205
|
idmap.update_attributes(last_push_to_external: Time.now, message: nil)
|
163
206
|
end
|
164
207
|
rescue => e
|
@@ -193,54 +236,56 @@ module Maestrano::Connector::Rails::Concerns::Entity
|
|
193
236
|
# * Maps not discarded entities and associates them with their idmap, or create one if there isn't any
|
194
237
|
# * Return a hash {connec_entities: [], external_entities: []}
|
195
238
|
def consolidate_and_map_data(connec_entities, external_entities, organization, opts={})
|
239
|
+
return consolidate_and_map_singleton(connec_entities, external_entities, organization, opts) if singleton?
|
240
|
+
|
196
241
|
mapped_external_entities = external_entities.map{|entity|
|
197
|
-
idmap =
|
242
|
+
idmap = find_idmap({external_id: get_id_from_external_entity_hash(entity), organization_id: organization.id})
|
198
243
|
# No idmap: creating one, nothing else to do
|
199
244
|
unless idmap
|
200
|
-
next {entity:
|
245
|
+
next {entity: map_to_connec(entity, organization), idmap: create_idmap_from_external_entity(entity, organization)}
|
201
246
|
end
|
202
247
|
|
203
248
|
# Not pushing entity to Connec!
|
204
249
|
next nil unless idmap.to_connec
|
205
250
|
|
206
251
|
# Entity has not been modified since its last push to connec!
|
207
|
-
if
|
208
|
-
Maestrano::Connector::Rails::ConnectorLogger.log('info', organization, "Discard #{@@external_name} #{self.external_entity_name} : #{entity}")
|
209
|
-
next nil
|
210
|
-
end
|
252
|
+
next nil if self.class.not_modified_since_last_push_to_connec(idmap, entity, self, organization)
|
211
253
|
|
212
254
|
# Check for conflict with entities from connec!
|
213
|
-
|
214
|
-
# We keep the most recently updated entity
|
215
|
-
if !opts[:connec_preemption].nil?
|
216
|
-
keep_external = !opts[:connec_preemption]
|
217
|
-
else
|
218
|
-
keep_external = connec_entity['updated_at'] < self.get_last_update_date_from_external_entity_hash(entity)
|
219
|
-
end
|
220
|
-
|
221
|
-
if keep_external
|
222
|
-
Maestrano::Connector::Rails::ConnectorLogger.log('info', organization, "Conflict between #{@@external_name} #{self.external_entity_name} #{entity} and Connec! #{self.connec_entity_name} #{connec_entity}. Entity from #{@@external_name} kept")
|
223
|
-
connec_entities.delete(connec_entity)
|
224
|
-
{entity: self.map_to_connec(entity, organization), idmap: idmap}
|
225
|
-
else
|
226
|
-
Maestrano::Connector::Rails::ConnectorLogger.log('info', organization, "Conflict between #{@@external_name} #{self.external_entity_name} #{entity} and Connec! #{self.connec_entity_name} #{connec_entity}. Entity from Connec! kept")
|
227
|
-
nil
|
228
|
-
end
|
229
|
-
|
230
|
-
else
|
231
|
-
{entity: self.map_to_connec(entity, organization), idmap: idmap}
|
232
|
-
end
|
255
|
+
self.class.solve_conflict(entity, self, connec_entities, connec_entity_name, idmap, organization, opts)
|
233
256
|
}
|
234
257
|
mapped_external_entities.compact!
|
235
258
|
|
236
259
|
mapped_connec_entities = connec_entities.map{|entity|
|
237
|
-
|
260
|
+
map_to_external_with_idmap(entity, organization)
|
238
261
|
}
|
239
262
|
mapped_connec_entities.compact!
|
240
263
|
|
241
264
|
return {connec_entities: mapped_connec_entities, external_entities: mapped_external_entities}
|
242
265
|
end
|
243
266
|
|
267
|
+
def consolidate_and_map_singleton(connec_entities, external_entities, organization, opts={})
|
268
|
+
return {connec_entities: [], external_entities: []} if external_entities.empty? && connec_entities.empty?
|
269
|
+
|
270
|
+
idmap = find_or_create_idmap({organization_id: organization.id})
|
271
|
+
|
272
|
+
if external_entities.empty?
|
273
|
+
keep_external = false
|
274
|
+
elsif connec_entities.empty?
|
275
|
+
keep_external = true
|
276
|
+
elsif !opts[:connec_preemption].nil?
|
277
|
+
keep_external = !opts[:connec_preemption]
|
278
|
+
else
|
279
|
+
keep_external = self.class.is_external_more_recent?(connec_entities.first, external_entities.first, self)
|
280
|
+
end
|
281
|
+
if keep_external
|
282
|
+
idmap.update(external_id: get_id_from_external_entity_hash(external_entities.first))
|
283
|
+
return {connec_entities: [], external_entities: [{entity: map_to_connec(external_entities.first, organization), idmap: idmap}]}
|
284
|
+
else
|
285
|
+
idmap.update(connec_id: connec_entities.first['id'])
|
286
|
+
return {connec_entities: [{entity: map_to_external(connec_entities.first, organization), idmap: idmap}], external_entities: []}
|
287
|
+
end
|
288
|
+
end
|
244
289
|
|
245
290
|
# ----------------------------------------------
|
246
291
|
# Entity specific methods
|
@@ -275,4 +320,47 @@ module Maestrano::Connector::Rails::Concerns::Entity
|
|
275
320
|
def object_name_from_external_entity_hash(entity)
|
276
321
|
raise "Not implemented"
|
277
322
|
end
|
323
|
+
|
324
|
+
|
325
|
+
# ----------------------------------------------
|
326
|
+
# Internal helper methods
|
327
|
+
# ----------------------------------------------
|
328
|
+
module ClassMethods
|
329
|
+
def not_modified_since_last_push_to_connec(idmap, entity, entity_instance, organization)
|
330
|
+
result = idmap.last_push_to_connec && idmap.last_push_to_connec > entity_instance.get_last_update_date_from_external_entity_hash(entity)
|
331
|
+
Maestrano::Connector::Rails::ConnectorLogger.log('info', organization, "Discard #{entity_instance.external_entity_name} : #{entity}") unless result
|
332
|
+
result
|
333
|
+
end
|
334
|
+
|
335
|
+
def is_external_more_recent?(connec_entity, external_entity, entity_instance)
|
336
|
+
connec_entity['updated_at'] < entity_instance.get_last_update_date_from_external_entity_hash(external_entity)
|
337
|
+
end
|
338
|
+
|
339
|
+
def solve_conflict(external_entity, entity_instance, connec_entities, connec_entity_name, idmap, organization, opts)
|
340
|
+
if idmap.connec_id && connec_entity = connec_entities.detect{|connec_entity| connec_entity['id'] == idmap.connec_id}
|
341
|
+
# We keep the most recently updated entity
|
342
|
+
if !opts[:connec_preemption].nil?
|
343
|
+
keep_external = !opts[:connec_preemption]
|
344
|
+
else
|
345
|
+
keep_external = is_external_more_recent?(connec_entity, external_entity, entity_instance)
|
346
|
+
end
|
347
|
+
|
348
|
+
if keep_external
|
349
|
+
Maestrano::Connector::Rails::ConnectorLogger.log('info', organization, "Conflict between #{entity_instance.external_entity_name} #{external_entity} and Connec! #{connec_entity_name} #{connec_entity}. Entity from external kept")
|
350
|
+
connec_entities.delete(connec_entity)
|
351
|
+
entity_instance.map_external_entity_with_idmap(external_entity, connec_entity_name, idmap, organization)
|
352
|
+
else
|
353
|
+
Maestrano::Connector::Rails::ConnectorLogger.log('info', organization, "Conflict between #{entity_instance.external_entity_name} #{external_entity} and Connec! #{connec_entity_name} #{connec_entity}. Entity from Connec! kept")
|
354
|
+
nil
|
355
|
+
end
|
356
|
+
|
357
|
+
else
|
358
|
+
entity_instance.map_external_entity_with_idmap(external_entity, connec_entity_name, idmap, organization)
|
359
|
+
end
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
def map_external_entity_with_idmap(external_entity, connec_entity_name, idmap, organization)
|
364
|
+
{entity: map_to_connec(external_entity, organization), idmap: idmap}
|
365
|
+
end
|
278
366
|
end
|