maestrano-connector-rails 1.0.4 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +3 -2
- data/LICENSE +1 -1
- data/VERSION +1 -1
- data/app/controllers/maestrano/connec_controller.rb +3 -3
- data/app/jobs/maestrano/connector/rails/all_synchronizations_job.rb +1 -1
- data/app/jobs/maestrano/connector/rails/push_to_connec_job.rb +3 -3
- data/app/jobs/maestrano/connector/rails/synchronization_job.rb +9 -8
- data/app/models/maestrano/connector/rails/concerns/complex_entity.rb +6 -6
- data/app/models/maestrano/connector/rails/concerns/entity.rb +24 -11
- data/app/models/maestrano/connector/rails/organization.rb +7 -2
- data/app/models/maestrano/connector/rails/synchronization.rb +1 -1
- data/db/migrate/20160614114401_add_date_filtering_limit_to_organization.rb +11 -0
- data/db/migrate/20160614160654_add_encryption_on_oauth_keys.rb +19 -0
- data/lib/generators/connector/install_generator.rb +1 -0
- data/lib/generators/connector/templates/complex_entity_example/person.rb +1 -1
- data/lib/generators/connector/templates/entity.rb +9 -3
- data/lib/generators/connector/templates/home.js +11 -0
- data/lib/generators/connector/templates/home_controller.rb +12 -1
- data/lib/generators/connector/templates/home_index.haml +11 -0
- data/maestrano-connector-rails.gemspec +21 -4
- data/release_notes.md +6 -0
- data/spec/dummy/config/settings.yml +37 -0
- data/spec/dummy/config/settings/development.yml +12 -0
- data/spec/dummy/config/settings/production.yml +1 -0
- data/spec/dummy/config/settings/test.yml +12 -0
- data/spec/dummy/config/settings/uat.yml +1 -0
- data/spec/dummy/db/schema.rb +11 -6
- data/spec/integration/connec_to_external_spec.rb +24 -2
- data/spec/models/entity_spec.rb +49 -8
- data/spec/models/organization_spec.rb +34 -1
- data/spec/models/synchronization_spec.rb +16 -7
- data/spec/spec_helper.rb +1 -0
- data/template/application.yml.sample +5 -0
- data/template/maestrano-connector-template.rb +3 -1
- data/template/settings/development.yml +2 -1
- data/template/settings/settings.yml +2 -1
- data/template/settings/test.yml +2 -1
- metadata +53 -3
- data/db/20160524112054_add_encryption_on_oauth_keys.rb +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d686a6327d19c9928de390fdff97b8a49314ee12
|
4
|
+
data.tar.gz: 24766745312ecf5dbdc9cabd262602ecaee2883f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 44eeb799a05babf52afa93d910dcabb1addc680609c9ad18b5347f2dbe5055e5e9d7edd317013c032691f84570865d2d9d83b16a732273777b48e919218fd9ee
|
7
|
+
data.tar.gz: 5f2e00125ac1c7e482015f705fff22f689ee1b5eade8eeb3c27031dbad863ab989972851e399c97384c3b7fc5d533564405b543748c424602b3f8ce7ac77a67a
|
data/Gemfile
CHANGED
@@ -7,8 +7,8 @@ gem 'sidekiq'
|
|
7
7
|
gem 'haml-rails'
|
8
8
|
gem 'bootstrap-sass'
|
9
9
|
gem 'autoprefixer-rails'
|
10
|
-
|
11
|
-
|
10
|
+
gem 'attr_encrypted', '~> 1.4.0'
|
11
|
+
gem 'config'
|
12
12
|
|
13
13
|
# Add dependencies to develop your gem here.
|
14
14
|
group :development do
|
@@ -21,4 +21,5 @@ group :development do
|
|
21
21
|
gem 'factory_girl_rails'
|
22
22
|
gem 'sqlite3'
|
23
23
|
gem 'shoulda-matchers'
|
24
|
+
gem 'timecop'
|
24
25
|
end
|
data/LICENSE
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0
|
1
|
+
1.1.0
|
@@ -18,10 +18,10 @@ class Maestrano::ConnecController < Maestrano::Rails::WebHookController
|
|
18
18
|
Maestrano::Connector::Rails::ConnectorLogger.log('info', organization, "Received entity from Connec! webhook: Entity=#{entity_name}, Data=#{entity}")
|
19
19
|
connec_client = Maestrano::Connector::Rails::ConnecHelper.get_client(organization)
|
20
20
|
external_client = Maestrano::Connector::Rails::External.get_client(organization)
|
21
|
-
|
21
|
+
last_synchronization_date = organization.last_synchronization_date
|
22
22
|
|
23
23
|
entity_instance = entity_class_hash[:class].new(organization, connec_client, external_client, {})
|
24
|
-
entity_instance.before_sync(
|
24
|
+
entity_instance.before_sync(last_synchronization_date)
|
25
25
|
|
26
26
|
# Build expected input for consolidate_and_map_data
|
27
27
|
if entity_class_hash[:is_complex]
|
@@ -33,7 +33,7 @@ class Maestrano::ConnecController < Maestrano::Rails::WebHookController
|
|
33
33
|
end
|
34
34
|
entity_instance.push_entities_to_external(mapped_entity[:connec_entities])
|
35
35
|
|
36
|
-
entity_instance.after_sync(
|
36
|
+
entity_instance.after_sync(last_synchronization_date)
|
37
37
|
end
|
38
38
|
end
|
39
39
|
rescue => e
|
@@ -4,7 +4,7 @@ module Maestrano::Connector::Rails
|
|
4
4
|
|
5
5
|
# Trigger synchronization of all active organizations
|
6
6
|
def perform(name=nil, count=nil)
|
7
|
-
Maestrano::Connector::Rails::Organization.where(
|
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
|
@@ -8,7 +8,7 @@ module Maestrano::Connector::Rails
|
|
8
8
|
|
9
9
|
connec_client = Maestrano::Connector::Rails::ConnecHelper.get_client(organization)
|
10
10
|
external_client = Maestrano::Connector::Rails::External.get_client(organization)
|
11
|
-
|
11
|
+
last_synchronization_date = organization.last_synchronization_date
|
12
12
|
|
13
13
|
entities_hash.each do |external_entity_name, entities|
|
14
14
|
if entity_instance_hash = find_entity_instance(external_entity_name, organization, connec_client, external_client, opts)
|
@@ -16,7 +16,7 @@ module Maestrano::Connector::Rails
|
|
16
16
|
|
17
17
|
entity_instance = entity_instance_hash[:instance]
|
18
18
|
|
19
|
-
entity_instance.before_sync(
|
19
|
+
entity_instance.before_sync(last_synchronization_date)
|
20
20
|
# Build expected input for consolidate_and_map_data
|
21
21
|
if entity_instance_hash[:is_complex]
|
22
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))
|
@@ -25,7 +25,7 @@ module Maestrano::Connector::Rails
|
|
25
25
|
end
|
26
26
|
entity_instance.push_entities_to_connec(mapped_entities[:external_entities])
|
27
27
|
|
28
|
-
entity_instance.after_sync(
|
28
|
+
entity_instance.after_sync(last_synchronization_date)
|
29
29
|
else
|
30
30
|
Rails.logger.warn "Called push to connec job with unknow entity: #{external_entity_name}"
|
31
31
|
end
|
@@ -29,6 +29,7 @@ module Maestrano::Connector::Rails
|
|
29
29
|
|
30
30
|
begin
|
31
31
|
last_synchronization = organization.last_successful_synchronization
|
32
|
+
last_synchronization_date = organization.last_synchronization_date
|
32
33
|
connec_client = ConnecHelper.get_client(organization)
|
33
34
|
external_client = External.get_client(organization)
|
34
35
|
|
@@ -38,7 +39,7 @@ module Maestrano::Connector::Rails
|
|
38
39
|
ConnectorLogger.log('info', organization, "First synchronization ever. Doing two half syncs to allow smart merging to work its magic.")
|
39
40
|
[{skip_connec: true}, {skip_external: true}].each do |opt|
|
40
41
|
organization.synchronized_entities.select{|k, v| v}.keys.each do |entity|
|
41
|
-
sync_entity(entity.to_s, organization, connec_client, external_client,
|
42
|
+
sync_entity(entity.to_s, organization, connec_client, external_client, last_synchronization_date, opts.merge(opt))
|
42
43
|
end
|
43
44
|
end
|
44
45
|
elsif opts[:only_entities]
|
@@ -46,11 +47,11 @@ module Maestrano::Connector::Rails
|
|
46
47
|
# The synchronization is marked as partial and will not be considered as the last-synchronization for the next sync
|
47
48
|
current_synchronization.set_partial
|
48
49
|
opts[:only_entities].each do |entity|
|
49
|
-
sync_entity(entity, organization, connec_client, external_client,
|
50
|
+
sync_entity(entity, organization, connec_client, external_client, last_synchronization_date, opts)
|
50
51
|
end
|
51
52
|
else
|
52
53
|
organization.synchronized_entities.select{|k, v| v}.keys.each do |entity|
|
53
|
-
sync_entity(entity.to_s, organization, connec_client, external_client,
|
54
|
+
sync_entity(entity.to_s, organization, connec_client, external_client, last_synchronization_date, opts)
|
54
55
|
end
|
55
56
|
end
|
56
57
|
|
@@ -62,16 +63,16 @@ module Maestrano::Connector::Rails
|
|
62
63
|
end
|
63
64
|
end
|
64
65
|
|
65
|
-
def sync_entity(entity_name, organization, connec_client, external_client,
|
66
|
+
def sync_entity(entity_name, organization, connec_client, external_client, last_synchronization_date, opts)
|
66
67
|
entity_instance = "Entities::#{entity_name.titleize.split.join}".constantize.new(organization, connec_client, external_client, opts.dup)
|
67
68
|
|
68
|
-
entity_instance.before_sync(
|
69
|
-
external_entities = entity_instance.get_external_entities_wrapper(
|
70
|
-
connec_entities = entity_instance.get_connec_entities(
|
69
|
+
entity_instance.before_sync(last_synchronization_date)
|
70
|
+
external_entities = entity_instance.get_external_entities_wrapper(last_synchronization_date)
|
71
|
+
connec_entities = entity_instance.get_connec_entities(last_synchronization_date)
|
71
72
|
mapped_entities = entity_instance.consolidate_and_map_data(connec_entities, external_entities)
|
72
73
|
entity_instance.push_entities_to_external(mapped_entities[:connec_entities])
|
73
74
|
entity_instance.push_entities_to_connec(mapped_entities[:external_entities])
|
74
|
-
entity_instance.after_sync(
|
75
|
+
entity_instance.after_sync(last_synchronization_date)
|
75
76
|
end
|
76
77
|
end
|
77
78
|
end
|
@@ -59,22 +59,22 @@ module Maestrano::Connector::Rails::Concerns::ComplexEntity
|
|
59
59
|
# -------------------------------------------------------------
|
60
60
|
# Entity equivalent methods
|
61
61
|
# -------------------------------------------------------------
|
62
|
-
def get_connec_entities(
|
62
|
+
def get_connec_entities(last_synchronization_date=nil)
|
63
63
|
entities = ActiveSupport::HashWithIndifferentAccess.new
|
64
64
|
|
65
65
|
self.class.connec_entities_names.each do |connec_entity_name|
|
66
66
|
sub_entity_instance = instantiate_sub_entity_instance(connec_entity_name)
|
67
|
-
entities[connec_entity_name] = sub_entity_instance.get_connec_entities(
|
67
|
+
entities[connec_entity_name] = sub_entity_instance.get_connec_entities(last_synchronization_date)
|
68
68
|
end
|
69
69
|
entities
|
70
70
|
end
|
71
71
|
|
72
|
-
def get_external_entities_wrapper(
|
72
|
+
def get_external_entities_wrapper(last_synchronization_date=nil)
|
73
73
|
entities = ActiveSupport::HashWithIndifferentAccess.new
|
74
74
|
|
75
75
|
self.class.external_entities_names.each do |external_entity_name|
|
76
76
|
sub_entity_instance = instantiate_sub_entity_instance(external_entity_name)
|
77
|
-
entities[external_entity_name] = sub_entity_instance.get_external_entities_wrapper(
|
77
|
+
entities[external_entity_name] = sub_entity_instance.get_external_entities_wrapper(last_synchronization_date)
|
78
78
|
end
|
79
79
|
entities
|
80
80
|
end
|
@@ -141,11 +141,11 @@ module Maestrano::Connector::Rails::Concerns::ComplexEntity
|
|
141
141
|
end
|
142
142
|
end
|
143
143
|
|
144
|
-
def before_sync(
|
144
|
+
def before_sync(last_synchronization_date)
|
145
145
|
# Does nothing by default
|
146
146
|
end
|
147
147
|
|
148
|
-
def after_sync(
|
148
|
+
def after_sync(last_synchronization_date)
|
149
149
|
# Does nothing by default
|
150
150
|
end
|
151
151
|
|
@@ -59,6 +59,10 @@ module Maestrano::Connector::Rails::Concerns::Entity
|
|
59
59
|
raise "Not implemented"
|
60
60
|
end
|
61
61
|
|
62
|
+
def creation_date_from_external_entity_hash(entity)
|
63
|
+
raise "Not implemented"
|
64
|
+
end
|
65
|
+
|
62
66
|
# Return a string representing the object from a connec! entity hash
|
63
67
|
def object_name_from_connec_entity_hash(entity)
|
64
68
|
raise "Not implemented"
|
@@ -154,7 +158,7 @@ module Maestrano::Connector::Rails::Concerns::Entity
|
|
154
158
|
# * full_sync
|
155
159
|
# * $filter (see Connec! documentation)
|
156
160
|
# * $orderby (see Connec! documentation)
|
157
|
-
def get_connec_entities(
|
161
|
+
def get_connec_entities(last_synchronization_date=nil)
|
158
162
|
return [] if @opts[:skip_connec] || !self.class.can_read_connec?
|
159
163
|
|
160
164
|
Maestrano::Connector::Rails::ConnectorLogger.log('info', @organization, "Fetching Connec! #{self.class.connec_entity_name}")
|
@@ -165,10 +169,10 @@ module Maestrano::Connector::Rails::Concerns::Entity
|
|
165
169
|
|
166
170
|
# Fetch first page
|
167
171
|
page_number = 0
|
168
|
-
if
|
172
|
+
if last_synchronization_date.blank? || @opts[:full_sync]
|
169
173
|
query_params[:$filter] = @opts[:$filter] if @opts[:$filter]
|
170
174
|
else
|
171
|
-
query_params[:$filter] = "updated_at gt '#{
|
175
|
+
query_params[:$filter] = "updated_at gt '#{last_synchronization_date.iso8601}'" + (@opts[:$filter] ? " and #{@opts[:$filter]}" : '')
|
172
176
|
end
|
173
177
|
|
174
178
|
Maestrano::Connector::Rails::ConnectorLogger.log('debug', @organization, "entity=#{self.class.connec_entity_name}, fetching data with #{query_params.to_query}")
|
@@ -219,12 +223,12 @@ module Maestrano::Connector::Rails::Concerns::Entity
|
|
219
223
|
# ----------------------------------------------
|
220
224
|
# External methods
|
221
225
|
# ----------------------------------------------
|
222
|
-
def get_external_entities_wrapper(
|
226
|
+
def get_external_entities_wrapper(last_synchronization_date=nil)
|
223
227
|
return [] if @opts[:skip_external] || !self.class.can_read_external?
|
224
|
-
get_external_entities(
|
228
|
+
get_external_entities(last_synchronization_date)
|
225
229
|
end
|
226
230
|
|
227
|
-
def get_external_entities(
|
231
|
+
def get_external_entities(last_synchronization_date=nil)
|
228
232
|
Maestrano::Connector::Rails::ConnectorLogger.log('info', @organization, "Fetching #{Maestrano::Connector::Rails::External.external_name} #{self.class.external_entity_name.pluralize}")
|
229
233
|
raise "Not implemented"
|
230
234
|
end
|
@@ -319,6 +323,9 @@ module Maestrano::Connector::Rails::Concerns::Entity
|
|
319
323
|
|
320
324
|
def consolidate_and_map_connec_entities(connec_entities, external_entities, references, external_entity_name)
|
321
325
|
connec_entities.map{|entity|
|
326
|
+
# Entity has been created before date filtering limit
|
327
|
+
next nil if before_date_filtering_limit?(entity, false) && !@opts[:full_sync]
|
328
|
+
|
322
329
|
entity = Maestrano::Connector::Rails::ConnecHelper.unfold_references(entity, references, @organization)
|
323
330
|
next nil unless entity
|
324
331
|
connec_id = entity.delete(:__connec_id)
|
@@ -332,7 +339,6 @@ module Maestrano::Connector::Rails::Concerns::Entity
|
|
332
339
|
idmap.update(name: self.class.object_name_from_connec_entity_hash(entity))
|
333
340
|
|
334
341
|
next nil if idmap.external_inactive || !idmap.to_external || (!@opts[:full_sync] && not_modified_since_last_push_to_external?(idmap, entity))
|
335
|
-
|
336
342
|
# Check for conflict with entities from external
|
337
343
|
solve_conflict(entity, external_entities, external_entity_name, idmap)
|
338
344
|
}.compact
|
@@ -340,6 +346,9 @@ module Maestrano::Connector::Rails::Concerns::Entity
|
|
340
346
|
|
341
347
|
def consolidate_and_map_external_entities(external_entities, connec_entity_name)
|
342
348
|
external_entities.map{|entity|
|
349
|
+
# Entity has been created before date filtering limit
|
350
|
+
next nil if before_date_filtering_limit?(entity) && !@opts[:full_sync]
|
351
|
+
|
343
352
|
entity_id = self.class.id_from_external_entity_hash(entity)
|
344
353
|
idmap = self.class.find_or_create_idmap(external_id: entity_id, organization_id: @organization.id, connec_entity: connec_entity_name.downcase)
|
345
354
|
|
@@ -389,11 +398,11 @@ module Maestrano::Connector::Rails::Concerns::Entity
|
|
389
398
|
# ----------------------------------------------
|
390
399
|
# After and before sync
|
391
400
|
# ----------------------------------------------
|
392
|
-
def before_sync(
|
401
|
+
def before_sync(last_synchronization_date)
|
393
402
|
# Does nothing by default
|
394
403
|
end
|
395
404
|
|
396
|
-
def after_sync(
|
405
|
+
def after_sync(last_synchronization_date)
|
397
406
|
# Does nothing by default
|
398
407
|
end
|
399
408
|
|
@@ -451,6 +460,10 @@ module Maestrano::Connector::Rails::Concerns::Entity
|
|
451
460
|
not_modified
|
452
461
|
end
|
453
462
|
|
463
|
+
def before_date_filtering_limit?(entity, external=true)
|
464
|
+
@organization.date_filtering_limit && @organization.date_filtering_limit > (external ? self.class.creation_date_from_external_entity_hash(entity) : entity['created_at'])
|
465
|
+
end
|
466
|
+
|
454
467
|
def is_connec_more_recent?(connec_entity, external_entity)
|
455
468
|
connec_entity['updated_at'] > self.class.last_update_date_from_external_entity_hash(external_entity)
|
456
469
|
end
|
@@ -465,11 +478,11 @@ module Maestrano::Connector::Rails::Concerns::Entity
|
|
465
478
|
end
|
466
479
|
|
467
480
|
if keep_connec
|
468
|
-
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
|
481
|
+
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")
|
469
482
|
external_entities.delete(external_entity)
|
470
483
|
map_connec_entity_with_idmap(connec_entity, external_entity_name, idmap)
|
471
484
|
else
|
472
|
-
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
|
485
|
+
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")
|
473
486
|
nil
|
474
487
|
end
|
475
488
|
|
@@ -20,8 +20,9 @@ module Maestrano::Connector::Rails
|
|
20
20
|
#===================================
|
21
21
|
# Encryptions
|
22
22
|
#===================================
|
23
|
-
|
24
|
-
|
23
|
+
attr_encrypted_options.merge!(:mode => :per_attribute_iv_and_salt)
|
24
|
+
attr_encrypted :oauth_token, key: ::Settings.encryption_key1
|
25
|
+
attr_encrypted :refresh_token, key: ::Settings.encryption_key2
|
25
26
|
|
26
27
|
#===================================
|
27
28
|
# Associations
|
@@ -74,5 +75,9 @@ module Maestrano::Connector::Rails
|
|
74
75
|
def last_successful_synchronization
|
75
76
|
self.synchronizations.where(status: 'SUCCESS', partial: false).order(updated_at: :desc).first
|
76
77
|
end
|
78
|
+
|
79
|
+
def last_synchronization_date
|
80
|
+
(last_successful_synchronization && last_successful_synchronization.updated_at) || date_filtering_limit
|
81
|
+
end
|
77
82
|
end
|
78
83
|
end
|
@@ -41,7 +41,7 @@ module Maestrano::Connector::Rails
|
|
41
41
|
def clean_synchronizations
|
42
42
|
count = self.organization.synchronizations.count
|
43
43
|
if count > 100
|
44
|
-
self.organization.synchronizations.limit(count - 100).destroy_all
|
44
|
+
self.organization.synchronizations.order('id ASC').limit(count - 100).destroy_all
|
45
45
|
end
|
46
46
|
end
|
47
47
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class AddDateFilteringLimitToOrganization < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
add_column :organizations, :date_filtering_limit, :datetime
|
4
|
+
add_column :organizations, :historical_data, :boolean, default: false
|
5
|
+
|
6
|
+
# Set historical data to true for organization existing before the feature
|
7
|
+
Maestrano::Connector::Rails::Organization.all.each do |o|
|
8
|
+
o.update(historical_data: true)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class AddEncryptionOnOauthKeys < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
tokens = Maestrano::Connector::Rails::Organization.map{|o|
|
4
|
+
{id: o.id, oauth_token: o.oauth_token, refresh_token: o.refresh_token}
|
5
|
+
}
|
6
|
+
|
7
|
+
rename_column :organizations, :oauth_token, :encrypted_oauth_token
|
8
|
+
add_column :organizations, :encrypted_oauth_token_iv, :string
|
9
|
+
add_column :organizations, :encrypted_oauth_token_salt, :string
|
10
|
+
rename_column :organizations, :refresh_token, :encrypted_refresh_token
|
11
|
+
add_column :organizations, :encrypted_refresh_token_iv, :string
|
12
|
+
add_column :organizations, :encrypted_refresh_token_salt, :string
|
13
|
+
|
14
|
+
tokens.each do |token|
|
15
|
+
o = Maestrano::Connector::Rails::Organization.find(token[:id])
|
16
|
+
o.update(oauth_token: token[:oauth_token], refresh_token: token[:refresh_token])
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -38,6 +38,7 @@ module Connector
|
|
38
38
|
copy_file 'home_controller.rb', 'app/controllers/home_controller.rb'
|
39
39
|
copy_file 'home_controller_spec.rb', 'spec/controllers/home_controller_spec.rb'
|
40
40
|
copy_file 'home_index.haml', 'app/views/home/index.html.haml'
|
41
|
+
copy_file 'home.js', 'app/assets/javascripts/home.js'
|
41
42
|
|
42
43
|
copy_file 'synchronizations_controller.rb', 'app/controllers/synchronizations_controller.rb'
|
43
44
|
copy_file 'synchronizations_controller_spec.rb', 'spec/controllers/synchronizations_controller_spec.rb'
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# TODO
|
2
2
|
# This file is provided as an example and should be removed
|
3
3
|
# See README for explanation
|
4
|
-
# class
|
4
|
+
# class Entities::SubEntities::Person < Maestrano::Connector::Rails::SubEntityBase
|
5
5
|
# def self.external?
|
6
6
|
# false
|
7
7
|
# end
|
@@ -8,11 +8,11 @@ class Maestrano::Connector::Rails::Entity
|
|
8
8
|
# * @opts
|
9
9
|
|
10
10
|
# Return an array of entities from the external app
|
11
|
-
def get_external_entities(
|
11
|
+
def get_external_entities(last_synchronization_date=nil)
|
12
12
|
Maestrano::Connector::Rails::ConnectorLogger.log('info', @organization, "Fetching #{Maestrano::Connector::Rails::External.external_name} #{self.class.external_entity_name.pluralize}")
|
13
13
|
# TODO
|
14
|
-
# This method should return only entities that have been updated since the
|
15
|
-
# It should also implements an option to do a full synchronization when @opts[:full_sync] == true or when there is no
|
14
|
+
# This method should return only entities that have been updated since the last_synchronization_date
|
15
|
+
# It should also implements an option to do a full synchronization when @opts[:full_sync] == true or when there is no last_synchronization_date
|
16
16
|
# Maestrano::Connector::Rails::ConnectorLogger.log('info', @organization, "Received data: Source=#{Maestrano::Connector::Rails::External.external_name}, Entity=#{self.class.external_entity_name}, Response=#{entities}")
|
17
17
|
end
|
18
18
|
|
@@ -40,6 +40,12 @@ class Maestrano::Connector::Rails::Entity
|
|
40
40
|
# e.g entity['last_update']
|
41
41
|
end
|
42
42
|
|
43
|
+
def self.creation_date_from_external_entity_hash(entity)
|
44
|
+
# TODO
|
45
|
+
# This method return the creation date from an external_entity_hash
|
46
|
+
# e.g entity['created_at']
|
47
|
+
end
|
48
|
+
|
43
49
|
def self.inactive_from_external_entity_hash?(entity)
|
44
50
|
# TODO
|
45
51
|
# This method return true is entity is inactive in the external application
|
@@ -0,0 +1,11 @@
|
|
1
|
+
function historicalDataDisplay()
|
2
|
+
{
|
3
|
+
if (document.getElementById('historical-data').checked)
|
4
|
+
{
|
5
|
+
document.getElementById('historical-data-display-checked').style.display = 'block';
|
6
|
+
document.getElementById('historical-data-display-unchecked').style.display = 'none';
|
7
|
+
} else {
|
8
|
+
document.getElementById('historical-data-display-unchecked').style.display = 'block';
|
9
|
+
document.getElementById('historical-data-display-checked').style.display = 'none';
|
10
|
+
}
|
11
|
+
}
|
@@ -13,9 +13,20 @@ class HomeController < ApplicationController
|
|
13
13
|
organization.synchronized_entities[entity] = !!params["#{entity}"]
|
14
14
|
end
|
15
15
|
organization.sync_enabled = organization.synchronized_entities.values.any?
|
16
|
+
|
17
|
+
unless organization.historical_data
|
18
|
+
historical_data = !!params['historical-data']
|
19
|
+
if historical_data
|
20
|
+
organization.date_filtering_limit = nil
|
21
|
+
organization.historical_data = true
|
22
|
+
else
|
23
|
+
organization.date_filtering_limit ||= Time.now
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
16
27
|
organization.save
|
17
28
|
|
18
|
-
if !old_sync_state
|
29
|
+
if !old_sync_state && organization.sync_enabled
|
19
30
|
Maestrano::Connector::Rails::SynchronizationJob.perform_later(organization, {})
|
20
31
|
flash[:info] = 'Congrats, you\'re all set up! Your data are now being synced'
|
21
32
|
end
|
@@ -57,6 +57,17 @@
|
|
57
57
|
.col-md-5.text-right
|
58
58
|
- if v && @organization.oauth_uid && @organization.sync_enabled
|
59
59
|
= link_to "Force a synchronization for #{k.to_s.humanize.pluralize} only", home_synchronize_path(opts: {only_entities: [k.to_s]}), method: :post, class: "btn btn-warning btn-sm"
|
60
|
+
.spacer1
|
61
|
+
.row
|
62
|
+
.col-md-4
|
63
|
+
%label{:for => 'historical-data'} Synchronize my historical data
|
64
|
+
.col-md-2
|
65
|
+
%input{type: 'checkbox', id: 'historical-data', name: 'historical-data', checked: @organization.historical_data, onchange: 'historicalDataDisplay();', disabled: @organization.historical_data}
|
66
|
+
.col-md-6
|
67
|
+
%small#historical-data-display-unchecked{style: "display: #{@organization.historical_data ? 'none' : 'block'}"} Only data created after #{(@organization.date_filtering_limit && @organization.date_filtering_limit.utc || Time.now.utc).to_formatted_s(:long_ordinal)} will be synchronized
|
68
|
+
%small#historical-data-display-checked{style: "display: #{!@organization.historical_data ? 'none' : 'block'}"}
|
69
|
+
Synchronizing your historical data will share all data in ApplicationName. This action is not reversible. Want to know more? Check
|
70
|
+
= link_to 'here', 'https://maestrano.atlassian.net/wiki/display/UKB/How+Connec%21+manages+Historical+Data+Sharing'
|
60
71
|
.spacer1
|
61
72
|
.row
|
62
73
|
.col-md-2.col-md-offset-10.text-center.link-step-action
|
@@ -2,16 +2,16 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: maestrano-connector-rails 1.0
|
5
|
+
# stub: maestrano-connector-rails 1.1.0 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "maestrano-connector-rails"
|
9
|
-
s.version = "1.0
|
9
|
+
s.version = "1.1.0"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib"]
|
13
13
|
s.authors = ["Pierre Berard"]
|
14
|
-
s.date = "2016-06-
|
14
|
+
s.date = "2016-06-17"
|
15
15
|
s.description = "Maestrano is the next generation marketplace for SME applications. See https://maestrano.com for details."
|
16
16
|
s.email = "pierre.berard@maestrano.com"
|
17
17
|
s.executables = ["rails"]
|
@@ -56,7 +56,6 @@ Gem::Specification.new do |s|
|
|
56
56
|
"app/models/maestrano/connector/rails/user_organization_rel.rb",
|
57
57
|
"bin/rails",
|
58
58
|
"config/routes.rb",
|
59
|
-
"db/20160524112054_add_encryption_on_oauth_keys.rb",
|
60
59
|
"db/migrate/20151122162100_create_users.rb",
|
61
60
|
"db/migrate/20151122162414_create_organizations.rb",
|
62
61
|
"db/migrate/20151122162613_create_user_organization_rels.rb",
|
@@ -65,6 +64,8 @@ Gem::Specification.new do |s|
|
|
65
64
|
"db/migrate/20160205132857_add_sync_enabled_to_organizations.rb",
|
66
65
|
"db/migrate/20160215103120_add_name_to_id_map.rb",
|
67
66
|
"db/migrate/20160427112250_add_inactive_to_idmaps.rb",
|
67
|
+
"db/migrate/20160614114401_add_date_filtering_limit_to_organization.rb",
|
68
|
+
"db/migrate/20160614160654_add_encryption_on_oauth_keys.rb",
|
68
69
|
"lib/generators/connector/USAGE",
|
69
70
|
"lib/generators/connector/complex_entity_generator.rb",
|
70
71
|
"lib/generators/connector/install_generator.rb",
|
@@ -78,6 +79,7 @@ Gem::Specification.new do |s|
|
|
78
79
|
"lib/generators/connector/templates/example_entity.rb",
|
79
80
|
"lib/generators/connector/templates/example_entity_spec.rb",
|
80
81
|
"lib/generators/connector/templates/external.rb",
|
82
|
+
"lib/generators/connector/templates/home.js",
|
81
83
|
"lib/generators/connector/templates/home_controller.rb",
|
82
84
|
"lib/generators/connector/templates/home_controller_spec.rb",
|
83
85
|
"lib/generators/connector/templates/home_index.haml",
|
@@ -145,6 +147,11 @@ Gem::Specification.new do |s|
|
|
145
147
|
"spec/dummy/config/locales/en.yml",
|
146
148
|
"spec/dummy/config/routes.rb",
|
147
149
|
"spec/dummy/config/secrets.yml",
|
150
|
+
"spec/dummy/config/settings.yml",
|
151
|
+
"spec/dummy/config/settings/development.yml",
|
152
|
+
"spec/dummy/config/settings/production.yml",
|
153
|
+
"spec/dummy/config/settings/test.yml",
|
154
|
+
"spec/dummy/config/settings/uat.yml",
|
148
155
|
"spec/dummy/db/schema.rb",
|
149
156
|
"spec/dummy/lib/assets/.keep",
|
150
157
|
"spec/dummy/log/.keep",
|
@@ -174,6 +181,7 @@ Gem::Specification.new do |s|
|
|
174
181
|
"spec/routing/connec_routing_spec.rb",
|
175
182
|
"spec/spec_helper.rb",
|
176
183
|
"template/Procfile",
|
184
|
+
"template/application.yml.sample",
|
177
185
|
"template/database.yml",
|
178
186
|
"template/factories.rb",
|
179
187
|
"template/gitignore",
|
@@ -204,6 +212,8 @@ Gem::Specification.new do |s|
|
|
204
212
|
s.add_runtime_dependency(%q<haml-rails>, [">= 0"])
|
205
213
|
s.add_runtime_dependency(%q<bootstrap-sass>, [">= 0"])
|
206
214
|
s.add_runtime_dependency(%q<autoprefixer-rails>, [">= 0"])
|
215
|
+
s.add_runtime_dependency(%q<attr_encrypted>, ["~> 1.4.0"])
|
216
|
+
s.add_runtime_dependency(%q<config>, [">= 0"])
|
207
217
|
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
208
218
|
s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
|
209
219
|
s.add_development_dependency(%q<bundler>, ["~> 1.0"])
|
@@ -213,6 +223,7 @@ Gem::Specification.new do |s|
|
|
213
223
|
s.add_development_dependency(%q<factory_girl_rails>, [">= 0"])
|
214
224
|
s.add_development_dependency(%q<sqlite3>, [">= 0"])
|
215
225
|
s.add_development_dependency(%q<shoulda-matchers>, [">= 0"])
|
226
|
+
s.add_development_dependency(%q<timecop>, [">= 0"])
|
216
227
|
else
|
217
228
|
s.add_dependency(%q<maestrano-rails>, [">= 0"])
|
218
229
|
s.add_dependency(%q<hash_mapper>, [">= 0"])
|
@@ -220,6 +231,8 @@ Gem::Specification.new do |s|
|
|
220
231
|
s.add_dependency(%q<haml-rails>, [">= 0"])
|
221
232
|
s.add_dependency(%q<bootstrap-sass>, [">= 0"])
|
222
233
|
s.add_dependency(%q<autoprefixer-rails>, [">= 0"])
|
234
|
+
s.add_dependency(%q<attr_encrypted>, ["~> 1.4.0"])
|
235
|
+
s.add_dependency(%q<config>, [">= 0"])
|
223
236
|
s.add_dependency(%q<shoulda>, [">= 0"])
|
224
237
|
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
225
238
|
s.add_dependency(%q<bundler>, ["~> 1.0"])
|
@@ -229,6 +242,7 @@ Gem::Specification.new do |s|
|
|
229
242
|
s.add_dependency(%q<factory_girl_rails>, [">= 0"])
|
230
243
|
s.add_dependency(%q<sqlite3>, [">= 0"])
|
231
244
|
s.add_dependency(%q<shoulda-matchers>, [">= 0"])
|
245
|
+
s.add_dependency(%q<timecop>, [">= 0"])
|
232
246
|
end
|
233
247
|
else
|
234
248
|
s.add_dependency(%q<maestrano-rails>, [">= 0"])
|
@@ -237,6 +251,8 @@ Gem::Specification.new do |s|
|
|
237
251
|
s.add_dependency(%q<haml-rails>, [">= 0"])
|
238
252
|
s.add_dependency(%q<bootstrap-sass>, [">= 0"])
|
239
253
|
s.add_dependency(%q<autoprefixer-rails>, [">= 0"])
|
254
|
+
s.add_dependency(%q<attr_encrypted>, ["~> 1.4.0"])
|
255
|
+
s.add_dependency(%q<config>, [">= 0"])
|
240
256
|
s.add_dependency(%q<shoulda>, [">= 0"])
|
241
257
|
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
242
258
|
s.add_dependency(%q<bundler>, ["~> 1.0"])
|
@@ -246,6 +262,7 @@ Gem::Specification.new do |s|
|
|
246
262
|
s.add_dependency(%q<factory_girl_rails>, [">= 0"])
|
247
263
|
s.add_dependency(%q<sqlite3>, [">= 0"])
|
248
264
|
s.add_dependency(%q<shoulda-matchers>, [">= 0"])
|
265
|
+
s.add_dependency(%q<timecop>, [">= 0"])
|
249
266
|
end
|
250
267
|
end
|
251
268
|
|
data/release_notes.md
CHANGED
@@ -0,0 +1,37 @@
|
|
1
|
+
encryption_key1: <%= ENV['encryption_key1'] %>
|
2
|
+
encryption_key2: <%= ENV['encryption_key2'] %>
|
3
|
+
|
4
|
+
# tenant config
|
5
|
+
default:
|
6
|
+
environment: 'production'
|
7
|
+
x509_certificate: "-----BEGIN CERTIFICATE-----\nMIIDezCCAuSgAwIBAgIJAPFpcH2rW0pyMA0GCSqGSIb3DQEBBQUAMIGGMQswCQYD\nVQQGEwJBVTEMMAoGA1UECBMDTlNXMQ8wDQYDVQQHEwZTeWRuZXkxGjAYBgNVBAoT\nEU1hZXN0cmFubyBQdHkgTHRkMRYwFAYDVQQDEw1tYWVzdHJhbm8uY29tMSQwIgYJ\nKoZIhvcNAQkBFhVzdXBwb3J0QG1hZXN0cmFuby5jb20wHhcNMTQwMTA0MDUyNDEw\nWhcNMzMxMjMwMDUyNDEwWjCBhjELMAkGA1UEBhMCQVUxDDAKBgNVBAgTA05TVzEP\nMA0GA1UEBxMGU3lkbmV5MRowGAYDVQQKExFNYWVzdHJhbm8gUHR5IEx0ZDEWMBQG\nA1UEAxMNbWFlc3RyYW5vLmNvbTEkMCIGCSqGSIb3DQEJARYVc3VwcG9ydEBtYWVz\ndHJhbm8uY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD3feNNn2xfEz5/\nQvkBIu2keh9NNhobpre8U4r1qC7h7OeInTldmxGL4cLHw4ZAqKbJVrlFWqNevM5V\nZBkDe4mjuVkK6rYK1ZK7eVk59BicRksVKRmdhXbANk/C5sESUsQv1wLZyrF5Iq8m\na9Oy4oYrIsEF2uHzCouTKM5n+O4DkwIDAQABo4HuMIHrMB0GA1UdDgQWBBSd/X0L\n/Pq+ZkHvItMtLnxMCAMdhjCBuwYDVR0jBIGzMIGwgBSd/X0L/Pq+ZkHvItMtLnxM\nCAMdhqGBjKSBiTCBhjELMAkGA1UEBhMCQVUxDDAKBgNVBAgTA05TVzEPMA0GA1UE\nBxMGU3lkbmV5MRowGAYDVQQKExFNYWVzdHJhbm8gUHR5IEx0ZDEWMBQGA1UEAxMN\nbWFlc3RyYW5vLmNvbTEkMCIGCSqGSIb3DQEJARYVc3VwcG9ydEBtYWVzdHJhbm8u\nY29tggkA8WlwfatbSnIwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQDE\nhe/18oRh8EqIhOl0bPk6BG49AkjhZZezrRJkCFp4dZxaBjwZTddwo8O5KHwkFGdy\nyLiPV326dtvXoKa9RFJvoJiSTQLEn5mO1NzWYnBMLtrDWojOe6Ltvn3x0HVo/iHh\nJShjAn6ZYX43Tjl1YXDd1H9O+7/VgEWAQQ32v8p5lA==\n-----END CERTIFICATE-----"
|
8
|
+
x509_fingerprint: '2f:57:71:e4:40:19:57:37:a6:2c:f0:c5:82:52:2f:2e:41:b7:9d:7e'
|
9
|
+
api_id: 'connec_api_id'
|
10
|
+
api_key: 'connec_api_key'
|
11
|
+
sso_init_path: '/maestrano/auth/saml/init/default'
|
12
|
+
sso_consume_path: '/maestrano/auth/saml/consume/default'
|
13
|
+
api_host: 'https://maestrano.com'
|
14
|
+
connec_host: 'https://api-connec.maestrano.com'
|
15
|
+
webhook:
|
16
|
+
account:
|
17
|
+
groups_path: '/maestrano/account/groups/:id/default'
|
18
|
+
group_users_path: '/maestrano/account/groups/:group_id/users/:id/default'
|
19
|
+
connec:
|
20
|
+
notifications_path: '/maestrano/connec/notifications/default'
|
21
|
+
|
22
|
+
maestrano-uat:
|
23
|
+
environment: 'uat'
|
24
|
+
x509_certificate: "-----BEGIN CERTIFICATE-----\nMIIDezCCAuSgAwIBAgIJAMzy+weDPp7qMA0GCSqGSIb3DQEBBQUAMIGGMQswCQYD\nVQQGEwJBVTEMMAoGA1UECBMDTlNXMQ8wDQYDVQQHEwZTeWRuZXkxGjAYBgNVBAoT\nEU1hZXN0cmFubyBQdHkgTHRkMRYwFAYDVQQDEw1tYWVzdHJhbm8uY29tMSQwIgYJ\nKoZIhvcNAQkBFhVzdXBwb3J0QG1hZXN0cmFuby5jb20wHhcNMTQwMTA0MDUyMzE0\nWhcNMzMxMjMwMDUyMzE0WjCBhjELMAkGA1UEBhMCQVUxDDAKBgNVBAgTA05TVzEP\nMA0GA1UEBxMGU3lkbmV5MRowGAYDVQQKExFNYWVzdHJhbm8gUHR5IEx0ZDEWMBQG\nA1UEAxMNbWFlc3RyYW5vLmNvbTEkMCIGCSqGSIb3DQEJARYVc3VwcG9ydEBtYWVz\ndHJhbm8uY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+2uyQeAOc/iro\nhCyT33RkkWfTGeJ8E/mu9F5ORWoCZ/h2J+QDuzuc69Rf1LoO4wZVQ8LBeWOqMBYz\notYFUIPlPfIBXDNL/stHkpg28WLDpoJM+46WpTAgp89YKgwdAoYODHiUOcO/uXOO\n2i9Ekoa+kxbvBzDJf7uuR/io6GERXwIDAQABo4HuMIHrMB0GA1UdDgQWBBTGRDBT\nie5+fHkB0+SZ5g3WY/D2RTCBuwYDVR0jBIGzMIGwgBTGRDBTie5+fHkB0+SZ5g3W\nY/D2RaGBjKSBiTCBhjELMAkGA1UEBhMCQVUxDDAKBgNVBAgTA05TVzEPMA0GA1UE\nBxMGU3lkbmV5MRowGAYDVQQKExFNYWVzdHJhbm8gUHR5IEx0ZDEWMBQGA1UEAxMN\nbWFlc3RyYW5vLmNvbTEkMCIGCSqGSIb3DQEJARYVc3VwcG9ydEBtYWVzdHJhbm8u\nY29tggkAzPL7B4M+nuowDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQAw\nRxg3rZrML//xbsS3FFXguzXiiNQAvA4KrMWhGh3jVrtzAlN1/okFNy6zuN8gzdKD\nYw2n0c/u3cSpUutIVZOkwQuPCMC1hoP7Ilat6icVewNcHayLBxKgRxpBhr5Sc4av\n3HOW5Bi/eyC7IjeBTbTnpziApEC7uUsBou2rlKmTGw==\n-----END CERTIFICATE-----"
|
25
|
+
x509_fingerprint: '8a:1e:2e:76:c4:67:80:68:6c:81:18:f7:d3:29:5d:77:f8:79:54:2f'
|
26
|
+
api_id: 'maestrano_uat_connec_api_id'
|
27
|
+
api_key: 'maestrano_uat_connec_api_key'
|
28
|
+
sso_consume_path: '/maestrano/auth/saml/consume/maestrano-uat'
|
29
|
+
sso_init_path: '/maestrano/auth/saml/init/maestrano-uat'
|
30
|
+
api_host: 'https://uat.maestrano.io'
|
31
|
+
connec_host: 'https://api-connec-uat.maestrano.io'
|
32
|
+
webhook:
|
33
|
+
account:
|
34
|
+
groups_path: '/maestrano/account/groups/:id/maestrano-uat'
|
35
|
+
group_users_path: '/maestrano/account/groups/:group_id/users/:id/maestrano-uat'
|
36
|
+
connec:
|
37
|
+
notifications_path: '/maestrano/connec/notifications/maestrano-uat'
|
@@ -0,0 +1,12 @@
|
|
1
|
+
app_host: 'http://localhost:3001/'
|
2
|
+
|
3
|
+
encryption_key1: 'This is a key that is 256 bits!!'
|
4
|
+
encryption_key2: 'This is a key that is 256 bits!!'
|
5
|
+
|
6
|
+
default:
|
7
|
+
api_host: 'https://maestrano.com'
|
8
|
+
connec_host: 'https://api-connec.maestrano.com'
|
9
|
+
|
10
|
+
maestrano-uat:
|
11
|
+
api_host: 'https://uat.maestrano.io'
|
12
|
+
connec_host: 'https://api-connec-uat.maestrano.io'
|
@@ -0,0 +1 @@
|
|
1
|
+
app_host: 'https://connector-xxx.herokuapp.com/'
|
@@ -0,0 +1,12 @@
|
|
1
|
+
app_host: 'http://localhost:3001/'
|
2
|
+
|
3
|
+
encryption_key1: 'This is a key that is 256 bits!!'
|
4
|
+
encryption_key2: 'This is a key that is 256 bits!!'
|
5
|
+
|
6
|
+
default:
|
7
|
+
environment: 'local'
|
8
|
+
api_host: 'http://localhost:3000'
|
9
|
+
|
10
|
+
maestrano-uat:
|
11
|
+
environment: 'local'
|
12
|
+
api_host: 'http://localhost:3000'
|
@@ -0,0 +1 @@
|
|
1
|
+
app_host: 'https://connector-xxx-uat.herokuapp.com/'
|
data/spec/dummy/db/schema.rb
CHANGED
@@ -11,7 +11,7 @@
|
|
11
11
|
#
|
12
12
|
# It's strongly recommended that you check this file into your version control system.
|
13
13
|
|
14
|
-
ActiveRecord::Schema.define(version:
|
14
|
+
ActiveRecord::Schema.define(version: 20160614152139) do
|
15
15
|
|
16
16
|
create_table "id_maps", force: :cascade do |t|
|
17
17
|
t.string "connec_id"
|
@@ -42,13 +42,18 @@ ActiveRecord::Schema.define(version: 20160427120963) do
|
|
42
42
|
t.string "oauth_provider"
|
43
43
|
t.string "oauth_uid"
|
44
44
|
t.string "oauth_name"
|
45
|
-
t.string "
|
46
|
-
t.string "
|
45
|
+
t.string "encrypted_oauth_token"
|
46
|
+
t.string "encrypted_refresh_token"
|
47
47
|
t.string "instance_url"
|
48
48
|
t.string "synchronized_entities"
|
49
|
-
t.datetime "created_at",
|
50
|
-
t.datetime "updated_at",
|
51
|
-
t.boolean "sync_enabled",
|
49
|
+
t.datetime "created_at", null: false
|
50
|
+
t.datetime "updated_at", null: false
|
51
|
+
t.boolean "sync_enabled", default: false
|
52
|
+
t.datetime "date_filtering_limit"
|
53
|
+
t.string "encrypted_oauth_token_iv"
|
54
|
+
t.string "encrypted_oauth_token_salt"
|
55
|
+
t.string "encrypted_refresh_token_iv"
|
56
|
+
t.string "encrypted_refresh_token_salt"
|
52
57
|
end
|
53
58
|
|
54
59
|
add_index "organizations", ["uid", "tenant"], name: "orga_uid_index"
|
@@ -64,7 +64,9 @@ describe 'connec to the external application' do
|
|
64
64
|
],
|
65
65
|
"is_customer" => false,
|
66
66
|
"is_supplier" => true,
|
67
|
-
"is_lead" => false
|
67
|
+
"is_lead" => false,
|
68
|
+
"updated_at" => 2.day.ago,
|
69
|
+
"created_at" => 2.day.ago
|
68
70
|
}
|
69
71
|
}
|
70
72
|
let(:person) { person1 }
|
@@ -77,7 +79,7 @@ describe 'connec to the external application' do
|
|
77
79
|
allow_any_instance_of(Entities::ConnecToExternal).to receive(:get_external_entities).and_return([])
|
78
80
|
}
|
79
81
|
|
80
|
-
subject { Maestrano::Connector::Rails::SynchronizationJob.new.sync_entity('connec_to_external', organization, connec_client, external_client,
|
82
|
+
subject { Maestrano::Connector::Rails::SynchronizationJob.new.sync_entity('connec_to_external', organization, connec_client, external_client, organization.last_synchronization_date, {}) }
|
81
83
|
|
82
84
|
describe 'a new record created in connec with all references known' do
|
83
85
|
before {
|
@@ -185,4 +187,24 @@ describe 'connec to the external application' do
|
|
185
187
|
}.to_not change{ Maestrano::Connector::Rails::IdMap.count }
|
186
188
|
end
|
187
189
|
end
|
190
|
+
|
191
|
+
describe 'an entity from before the date filtering limit' do
|
192
|
+
let(:date_filtering_limit) { 2.minute.ago }
|
193
|
+
before {
|
194
|
+
organization.update(date_filtering_limit: date_filtering_limit)
|
195
|
+
}
|
196
|
+
|
197
|
+
it 'calls get_connec_entities with a date even if there is no last sync' do
|
198
|
+
expect_any_instance_of(Entities::ConnecToExternal).to receive(:get_connec_entities).with(date_filtering_limit).and_return([])
|
199
|
+
subject
|
200
|
+
end
|
201
|
+
|
202
|
+
it 'pushes nothing and creates no idmap' do
|
203
|
+
expect_any_instance_of(Entities::ConnecToExternal).to_not receive(:create_external_entity)
|
204
|
+
expect_any_instance_of(Entities::ConnecToExternal).to_not receive(:update_external_entity)
|
205
|
+
expect{
|
206
|
+
subject
|
207
|
+
}.to_not change{ Maestrano::Connector::Rails::IdMap.count }
|
208
|
+
end
|
209
|
+
end
|
188
210
|
end
|
data/spec/models/entity_spec.rb
CHANGED
@@ -76,6 +76,10 @@ describe Maestrano::Connector::Rails::Entity do
|
|
76
76
|
it { expect{ subject.last_update_date_from_external_entity_hash(nil) }.to raise_error('Not implemented') }
|
77
77
|
end
|
78
78
|
|
79
|
+
describe 'creation_date_from_external_entity_hash' do
|
80
|
+
it { expect{ subject.creation_date_from_external_entity_hash(nil) }.to raise_error('Not implemented') }
|
81
|
+
end
|
82
|
+
|
79
83
|
# Entity specific methods
|
80
84
|
describe 'singleton?' do
|
81
85
|
it 'is false by default' do
|
@@ -166,7 +170,7 @@ describe Maestrano::Connector::Rails::Entity do
|
|
166
170
|
|
167
171
|
# Connec! methods
|
168
172
|
describe 'connec_methods' do
|
169
|
-
let(:sync) { create(:synchronization) }
|
173
|
+
let(:sync) { create(:synchronization, organization: organization) }
|
170
174
|
|
171
175
|
describe 'filter_connec_entities' do
|
172
176
|
it 'does nothing by default' do
|
@@ -211,7 +215,7 @@ describe Maestrano::Connector::Rails::Entity do
|
|
211
215
|
let(:opts) { {full_sync: true} }
|
212
216
|
it 'performs a full get' do
|
213
217
|
expect(connec_client).to receive(:get).with("#{connec_name.downcase.pluralize}?")
|
214
|
-
subject.get_connec_entities(sync)
|
218
|
+
subject.get_connec_entities(sync.updated_at)
|
215
219
|
end
|
216
220
|
end
|
217
221
|
|
@@ -226,7 +230,7 @@ describe Maestrano::Connector::Rails::Entity do
|
|
226
230
|
it 'performs a time limited get' do
|
227
231
|
uri_param = {"$filter" => "updated_at gt '#{sync.updated_at.iso8601}'"}.to_query
|
228
232
|
expect(connec_client).to receive(:get).with("#{connec_name.downcase.pluralize}?#{uri_param}")
|
229
|
-
subject.get_connec_entities(sync)
|
233
|
+
subject.get_connec_entities(sync.updated_at)
|
230
234
|
end
|
231
235
|
end
|
232
236
|
|
@@ -235,21 +239,21 @@ describe Maestrano::Connector::Rails::Entity do
|
|
235
239
|
subject.instance_variable_set(:@opts, {full_sync: true, :$filter => "code eq 'PEO12'"})
|
236
240
|
uri_param = {'$filter'=>'code eq \'PEO12\''}.to_query
|
237
241
|
expect(connec_client).to receive(:get).with("#{connec_name.downcase.pluralize}?#{uri_param}")
|
238
|
-
subject.get_connec_entities(sync)
|
242
|
+
subject.get_connec_entities(sync.updated_at)
|
239
243
|
end
|
240
244
|
|
241
245
|
it 'support filter option for time limited sync' do
|
242
246
|
subject.instance_variable_set(:@opts, {:$filter => "code eq 'PEO12'"})
|
243
247
|
uri_param = {"$filter"=>"updated_at gt '#{sync.updated_at.iso8601}' and code eq 'PEO12'"}.to_query
|
244
248
|
expect(connec_client).to receive(:get).with("#{connec_name.downcase.pluralize}?#{uri_param}")
|
245
|
-
subject.get_connec_entities(sync)
|
249
|
+
subject.get_connec_entities(sync.updated_at)
|
246
250
|
end
|
247
251
|
|
248
252
|
it 'support orderby option for time limited sync' do
|
249
253
|
subject.instance_variable_set(:@opts, {:$orderby => "name asc"})
|
250
254
|
uri_param = {"$orderby"=>"name asc", "$filter"=>"updated_at gt '#{sync.updated_at.iso8601}'"}.to_query
|
251
255
|
expect(connec_client).to receive(:get).with("#{connec_name.downcase.pluralize}?#{uri_param}")
|
252
|
-
subject.get_connec_entities(sync)
|
256
|
+
subject.get_connec_entities(sync.updated_at)
|
253
257
|
end
|
254
258
|
end
|
255
259
|
|
@@ -620,6 +624,7 @@ describe Maestrano::Connector::Rails::Entity do
|
|
620
624
|
before {
|
621
625
|
allow(subject.class).to receive(:id_from_external_entity_hash).and_return(id)
|
622
626
|
allow(subject.class).to receive(:last_update_date_from_external_entity_hash).and_return(date)
|
627
|
+
allow(subject.class).to receive(:creation_date_from_external_entity_hash).and_return(date)
|
623
628
|
}
|
624
629
|
|
625
630
|
describe 'consolidate_and_map_data' do
|
@@ -726,8 +731,8 @@ describe Maestrano::Connector::Rails::Entity do
|
|
726
731
|
let(:id2) { nil }
|
727
732
|
let(:connec_id1) { 'connec-id-1' }
|
728
733
|
let(:connec_id2) { 'connec-id-2' }
|
729
|
-
let(:entity1) { {'id' => id1, 'name' => 'John', 'updated_at' => date} }
|
730
|
-
let(:entity2) { {'id' => id2, 'name' => 'Jane', 'updated_at' => date} }
|
734
|
+
let(:entity1) { {'id' => id1, 'name' => 'John', 'updated_at' => date, 'created_at' => date} }
|
735
|
+
let(:entity2) { {'id' => id2, 'name' => 'Jane', 'updated_at' => date, 'created_at' => date} }
|
731
736
|
let(:entity_without_refs) { {} }
|
732
737
|
let(:entities) { [entity1, entity2] }
|
733
738
|
before {
|
@@ -788,6 +793,24 @@ describe Maestrano::Connector::Rails::Entity do
|
|
788
793
|
end
|
789
794
|
end
|
790
795
|
|
796
|
+
context 'when before date_filtering_limit' do
|
797
|
+
before {
|
798
|
+
organization.update(date_filtering_limit: 5.minutes.ago)
|
799
|
+
}
|
800
|
+
|
801
|
+
it 'discards the entity' do
|
802
|
+
expect(subject.consolidate_and_map_connec_entities(entities, [], [], external_name)).to eql([])
|
803
|
+
end
|
804
|
+
|
805
|
+
context 'with full synchronization opts' do
|
806
|
+
let(:opts) { {full_sync: true} }
|
807
|
+
|
808
|
+
it 'keeps the entity' do
|
809
|
+
expect(subject.consolidate_and_map_connec_entities(entities, [], [], external_name)).to eql([{entity: {mapped: 'entity'}, idmap: idmap1}])
|
810
|
+
end
|
811
|
+
end
|
812
|
+
end
|
813
|
+
|
791
814
|
end
|
792
815
|
|
793
816
|
context 'when conflict' do
|
@@ -906,6 +929,24 @@ describe Maestrano::Connector::Rails::Entity do
|
|
906
929
|
end
|
907
930
|
end
|
908
931
|
|
932
|
+
context 'when before date_filtering_limit' do
|
933
|
+
before {
|
934
|
+
organization.update(date_filtering_limit: 5.minutes.ago)
|
935
|
+
}
|
936
|
+
|
937
|
+
it 'discards the entity' do
|
938
|
+
expect(subject.consolidate_and_map_external_entities([entity], connec_name)).to eql([])
|
939
|
+
end
|
940
|
+
|
941
|
+
context 'with full synchronization opts' do
|
942
|
+
let(:opts) { {full_sync: true} }
|
943
|
+
|
944
|
+
it 'keeps the entity' do
|
945
|
+
expect(subject.consolidate_and_map_external_entities([entity], connec_name)).to eql([{entity: {mapped: 'ext_entity'}, idmap: idmap}])
|
946
|
+
end
|
947
|
+
end
|
948
|
+
end
|
949
|
+
|
909
950
|
end
|
910
951
|
end
|
911
952
|
end
|
@@ -137,12 +137,45 @@ describe Maestrano::Connector::Rails::Organization do
|
|
137
137
|
describe 'last_successful_synchronization' do
|
138
138
|
let!(:running_sync) { create(:synchronization, organization: subject, status: 'RUNNING') }
|
139
139
|
let!(:failed_sync) { create(:synchronization, organization: subject, status: 'ERROR') }
|
140
|
-
let!(:success_sync) { create(:synchronization, organization: subject, status: 'SUCCESS') }
|
140
|
+
let!(:success_sync) { create(:synchronization, organization: subject, status: 'SUCCESS', updated_at: 1.minute.ago) }
|
141
141
|
let!(:success_sync2) { create(:synchronization, organization: subject, status: 'SUCCESS', updated_at: 3.hours.ago) }
|
142
142
|
let!(:partial) { create(:synchronization, organization: subject, status: 'SUCCESS', partial: true) }
|
143
143
|
|
144
144
|
it { expect(subject.last_successful_synchronization).to eql(success_sync) }
|
145
145
|
end
|
146
|
+
|
147
|
+
describe 'last_synchronization_date' do
|
148
|
+
let(:date) { 2.days.ago }
|
149
|
+
|
150
|
+
context 'with date_filtering_limit' do
|
151
|
+
before {
|
152
|
+
subject.date_filtering_limit = date
|
153
|
+
}
|
154
|
+
|
155
|
+
it { expect(subject.last_synchronization_date).to eql(date) }
|
156
|
+
end
|
157
|
+
|
158
|
+
context 'with sync' do
|
159
|
+
let!(:success_sync) { create(:synchronization, organization: subject, status: 'SUCCESS') }
|
160
|
+
|
161
|
+
it { expect(subject.last_synchronization_date.to_date).to eql(success_sync.updated_at.to_date) }
|
162
|
+
end
|
163
|
+
|
164
|
+
context 'with both' do
|
165
|
+
let!(:success_sync) { create(:synchronization, organization: subject, status: 'SUCCESS') }
|
166
|
+
before {
|
167
|
+
subject.date_filtering_limit = date
|
168
|
+
}
|
169
|
+
|
170
|
+
it 'returns the sync date' do
|
171
|
+
expect(subject.last_synchronization_date.to_date).to eql(success_sync.updated_at.to_date)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
context 'with none' do
|
176
|
+
it { expect(subject.last_synchronization_date).to eql(nil) }
|
177
|
+
end
|
178
|
+
end
|
146
179
|
end
|
147
180
|
|
148
181
|
|
@@ -72,25 +72,34 @@ describe Maestrano::Connector::Rails::Synchronization do
|
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
75
|
-
describe 'clean_synchronizations' do
|
75
|
+
describe 'clean_synchronizations on creation' do
|
76
76
|
let!(:organization) { create(:organization) }
|
77
|
-
let!(:sync) { create(:synchronization, organization: organization) }
|
78
|
-
let!(:sync2) { create(:synchronization, organization: organization) }
|
79
77
|
|
80
78
|
context 'when less than 100 syncs' do
|
79
|
+
before {
|
80
|
+
2.times do
|
81
|
+
create(:synchronization, organization: organization)
|
82
|
+
end
|
83
|
+
}
|
84
|
+
|
81
85
|
it 'does nothing' do
|
82
|
-
expect{
|
86
|
+
expect{ organization.synchronizations.create(status: 'RUNNING') }.to change{ organization.synchronizations.count }.by(1)
|
83
87
|
end
|
84
88
|
end
|
85
89
|
|
86
90
|
context 'when more than 100 syncs' do
|
87
91
|
before {
|
88
|
-
|
92
|
+
100.times do
|
93
|
+
create(:synchronization, organization: organization)
|
94
|
+
end
|
89
95
|
}
|
90
96
|
|
91
|
-
it 'destroy the
|
92
|
-
|
97
|
+
it 'destroy the right syncs' do
|
98
|
+
sync = organization.synchronizations.create(status: 'RUNNING')
|
99
|
+
expect(Maestrano::Connector::Rails::Synchronization.count).to eql(100)
|
100
|
+
expect(Maestrano::Connector::Rails::Synchronization.all.map(&:id)).to eql([*2..101])
|
93
101
|
end
|
102
|
+
|
94
103
|
end
|
95
104
|
end
|
96
105
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -47,7 +47,7 @@ gem 'uglifier', '>= 1.3.0'
|
|
47
47
|
|
48
48
|
gem 'maestrano-connector-rails'
|
49
49
|
gem 'config'
|
50
|
-
|
50
|
+
gem 'attr_encrypted', '~> 1.4.0'
|
51
51
|
|
52
52
|
# Background jobs
|
53
53
|
gem 'sinatra', :require => nil
|
@@ -113,6 +113,8 @@ after_bundle do
|
|
113
113
|
end
|
114
114
|
copy_file 'settings/settings.yml', 'config/settings.yml'
|
115
115
|
|
116
|
+
copy_file 'application.yml.sample', 'config/application.yml.sample'
|
117
|
+
|
116
118
|
application do <<-RUBY
|
117
119
|
config.generators do |g|
|
118
120
|
g.test_framework :rspec, fixture: false
|
data/template/settings/test.yml
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: maestrano-connector-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pierre Berard
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-06-
|
11
|
+
date: 2016-06-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: maestrano-rails
|
@@ -94,6 +94,34 @@ dependencies:
|
|
94
94
|
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: attr_encrypted
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 1.4.0
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 1.4.0
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: config
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
97
125
|
- !ruby/object:Gem::Dependency
|
98
126
|
name: shoulda
|
99
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -220,6 +248,20 @@ dependencies:
|
|
220
248
|
- - ">="
|
221
249
|
- !ruby/object:Gem::Version
|
222
250
|
version: '0'
|
251
|
+
- !ruby/object:Gem::Dependency
|
252
|
+
name: timecop
|
253
|
+
requirement: !ruby/object:Gem::Requirement
|
254
|
+
requirements:
|
255
|
+
- - ">="
|
256
|
+
- !ruby/object:Gem::Version
|
257
|
+
version: '0'
|
258
|
+
type: :development
|
259
|
+
prerelease: false
|
260
|
+
version_requirements: !ruby/object:Gem::Requirement
|
261
|
+
requirements:
|
262
|
+
- - ">="
|
263
|
+
- !ruby/object:Gem::Version
|
264
|
+
version: '0'
|
223
265
|
description: Maestrano is the next generation marketplace for SME applications. See
|
224
266
|
https://maestrano.com for details.
|
225
267
|
email: pierre.berard@maestrano.com
|
@@ -266,7 +308,6 @@ files:
|
|
266
308
|
- app/models/maestrano/connector/rails/user_organization_rel.rb
|
267
309
|
- bin/rails
|
268
310
|
- config/routes.rb
|
269
|
-
- db/20160524112054_add_encryption_on_oauth_keys.rb
|
270
311
|
- db/migrate/20151122162100_create_users.rb
|
271
312
|
- db/migrate/20151122162414_create_organizations.rb
|
272
313
|
- db/migrate/20151122162613_create_user_organization_rels.rb
|
@@ -275,6 +316,8 @@ files:
|
|
275
316
|
- db/migrate/20160205132857_add_sync_enabled_to_organizations.rb
|
276
317
|
- db/migrate/20160215103120_add_name_to_id_map.rb
|
277
318
|
- db/migrate/20160427112250_add_inactive_to_idmaps.rb
|
319
|
+
- db/migrate/20160614114401_add_date_filtering_limit_to_organization.rb
|
320
|
+
- db/migrate/20160614160654_add_encryption_on_oauth_keys.rb
|
278
321
|
- lib/generators/connector/USAGE
|
279
322
|
- lib/generators/connector/complex_entity_generator.rb
|
280
323
|
- lib/generators/connector/install_generator.rb
|
@@ -288,6 +331,7 @@ files:
|
|
288
331
|
- lib/generators/connector/templates/example_entity.rb
|
289
332
|
- lib/generators/connector/templates/example_entity_spec.rb
|
290
333
|
- lib/generators/connector/templates/external.rb
|
334
|
+
- lib/generators/connector/templates/home.js
|
291
335
|
- lib/generators/connector/templates/home_controller.rb
|
292
336
|
- lib/generators/connector/templates/home_controller_spec.rb
|
293
337
|
- lib/generators/connector/templates/home_index.haml
|
@@ -355,6 +399,11 @@ files:
|
|
355
399
|
- spec/dummy/config/locales/en.yml
|
356
400
|
- spec/dummy/config/routes.rb
|
357
401
|
- spec/dummy/config/secrets.yml
|
402
|
+
- spec/dummy/config/settings.yml
|
403
|
+
- spec/dummy/config/settings/development.yml
|
404
|
+
- spec/dummy/config/settings/production.yml
|
405
|
+
- spec/dummy/config/settings/test.yml
|
406
|
+
- spec/dummy/config/settings/uat.yml
|
358
407
|
- spec/dummy/db/schema.rb
|
359
408
|
- spec/dummy/lib/assets/.keep
|
360
409
|
- spec/dummy/log/.keep
|
@@ -384,6 +433,7 @@ files:
|
|
384
433
|
- spec/routing/connec_routing_spec.rb
|
385
434
|
- spec/spec_helper.rb
|
386
435
|
- template/Procfile
|
436
|
+
- template/application.yml.sample
|
387
437
|
- template/database.yml
|
388
438
|
- template/factories.rb
|
389
439
|
- template/gitignore
|
@@ -1,8 +0,0 @@
|
|
1
|
-
class AddEncryptionOnOauthKeys < ActiveRecord::Migration
|
2
|
-
def change
|
3
|
-
rename_column :organizations, :oauth_token, :encrypted_oauth_token
|
4
|
-
add_column :organizations, :encrypted_oauth_token_iv, :string
|
5
|
-
rename_column :organizations, :refresh_token, :encrypted_refresh_token
|
6
|
-
add_column :organizations, :encrypted_refresh_token_iv, :string
|
7
|
-
end
|
8
|
-
end
|