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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -2
  3. data/LICENSE +1 -1
  4. data/VERSION +1 -1
  5. data/app/controllers/maestrano/connec_controller.rb +3 -3
  6. data/app/jobs/maestrano/connector/rails/all_synchronizations_job.rb +1 -1
  7. data/app/jobs/maestrano/connector/rails/push_to_connec_job.rb +3 -3
  8. data/app/jobs/maestrano/connector/rails/synchronization_job.rb +9 -8
  9. data/app/models/maestrano/connector/rails/concerns/complex_entity.rb +6 -6
  10. data/app/models/maestrano/connector/rails/concerns/entity.rb +24 -11
  11. data/app/models/maestrano/connector/rails/organization.rb +7 -2
  12. data/app/models/maestrano/connector/rails/synchronization.rb +1 -1
  13. data/db/migrate/20160614114401_add_date_filtering_limit_to_organization.rb +11 -0
  14. data/db/migrate/20160614160654_add_encryption_on_oauth_keys.rb +19 -0
  15. data/lib/generators/connector/install_generator.rb +1 -0
  16. data/lib/generators/connector/templates/complex_entity_example/person.rb +1 -1
  17. data/lib/generators/connector/templates/entity.rb +9 -3
  18. data/lib/generators/connector/templates/home.js +11 -0
  19. data/lib/generators/connector/templates/home_controller.rb +12 -1
  20. data/lib/generators/connector/templates/home_index.haml +11 -0
  21. data/maestrano-connector-rails.gemspec +21 -4
  22. data/release_notes.md +6 -0
  23. data/spec/dummy/config/settings.yml +37 -0
  24. data/spec/dummy/config/settings/development.yml +12 -0
  25. data/spec/dummy/config/settings/production.yml +1 -0
  26. data/spec/dummy/config/settings/test.yml +12 -0
  27. data/spec/dummy/config/settings/uat.yml +1 -0
  28. data/spec/dummy/db/schema.rb +11 -6
  29. data/spec/integration/connec_to_external_spec.rb +24 -2
  30. data/spec/models/entity_spec.rb +49 -8
  31. data/spec/models/organization_spec.rb +34 -1
  32. data/spec/models/synchronization_spec.rb +16 -7
  33. data/spec/spec_helper.rb +1 -0
  34. data/template/application.yml.sample +5 -0
  35. data/template/maestrano-connector-template.rb +3 -1
  36. data/template/settings/development.yml +2 -1
  37. data/template/settings/settings.yml +2 -1
  38. data/template/settings/test.yml +2 -1
  39. metadata +53 -3
  40. 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: 4b5dba94b691f6b3af1ac41b6a7d0398ee5396af
4
- data.tar.gz: dc4611f5da086cff9fc297b0d0d0eba7aa4e5c8d
3
+ metadata.gz: d686a6327d19c9928de390fdff97b8a49314ee12
4
+ data.tar.gz: 24766745312ecf5dbdc9cabd262602ecaee2883f
5
5
  SHA512:
6
- metadata.gz: 4b2683f1f4283965f1f4a4c81be839aaa72d734432aa6246d21d2dbf15e90be0161d11a8e863584863531c15af823a2375f38acd667a212733793d47fc32ad57
7
- data.tar.gz: d7931fb298a3b542c4a9878ccb6e5b2969efa4b67eb11c47aef601b50ff681d3539d013ed25e3934c129f55a9bb3b992a269fa81e7031fe75c8dbbda5e5f7088
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
- # gem 'attr_encrypted', '~> 3.0.0'
11
- # gem 'config'
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
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2015 Maestrano
3
+ Copyright (c) 2016 Maestrano
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.4
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
- last_synchronization = organization.last_successful_synchronization
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(last_synchronization)
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(last_synchronization)
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('oauth_provider IS NOT NULL AND oauth_token IS NOT NULL').each do |o|
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
- last_synchronization = organization.last_successful_synchronization
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(last_synchronization)
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(last_synchronization)
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, last_synchronization, opts.merge(opt))
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, last_synchronization, opts)
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, last_synchronization, opts)
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, last_synchronization, opts)
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(last_synchronization)
69
- external_entities = entity_instance.get_external_entities_wrapper(last_synchronization)
70
- connec_entities = entity_instance.get_connec_entities(last_synchronization)
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(last_synchronization)
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(last_synchronization)
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(last_synchronization)
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(last_synchronization)
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(last_synchronization)
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(last_synchronization)
144
+ def before_sync(last_synchronization_date)
145
145
  # Does nothing by default
146
146
  end
147
147
 
148
- def after_sync(last_synchronization)
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(last_synchronization)
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 last_synchronization.blank? || @opts[:full_sync]
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 '#{last_synchronization.updated_at.iso8601}'" + (@opts[:$filter] ? " and #{@opts[:$filter]}" : '')
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(last_synchronization)
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(last_synchronization)
228
+ get_external_entities(last_synchronization_date)
225
229
  end
226
230
 
227
- def get_external_entities(last_synchronization)
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(last_synchronization)
401
+ def before_sync(last_synchronization_date)
393
402
  # Does nothing by default
394
403
  end
395
404
 
396
- def after_sync(last_synchronization)
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 external kept")
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 Connec! kept")
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
- # attr_encrypted :oauth_token, key: ::Settings.encryption_key
24
- # attr_encrypted :refresh_token, key: ::Settings.encryption_key
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 Enities::SubEntities::Person < Maestrano::Connector::Rails::SubEntityBase
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(last_synchronization)
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 last_synchronization
15
- # It should also implements an option to do a full synchronization when @opts[:full_sync] == true or when there is no last_synchronization
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.4 ruby lib
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.4"
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-07"
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
 
@@ -1,3 +1,9 @@
1
+ ## 1.0.4
2
+
3
+ ### Fixes
4
+ * Fix uneeded creation of idmap for Connec! entities following a failure
5
+ * Fix Connec! pagination
6
+
1
7
  ## 1.0.3
2
8
 
3
9
  ### Fixes
@@ -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/'
@@ -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: 20160427120963) do
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 "oauth_token"
46
- t.string "refresh_token"
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", null: false
50
- t.datetime "updated_at", null: false
51
- t.boolean "sync_enabled", default: false
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, nil, {}) }
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
@@ -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{ sync.clean_synchronizations }.to_not change{ organization.synchronizations.count }
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
- allow_any_instance_of(ActiveRecord::Associations::CollectionProxy).to receive(:count).and_return(102)
92
+ 100.times do
93
+ create(:synchronization, organization: organization)
94
+ end
89
95
  }
90
96
 
91
- it 'destroy the idmaps' do
92
- expect{ sync.clean_synchronizations }.to change{ Maestrano::Connector::Rails::Synchronization.count }.by(-2)
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
@@ -5,6 +5,7 @@ require 'rspec/rails'
5
5
  require 'factory_girl_rails'
6
6
  require 'shoulda/matchers'
7
7
  require 'simplecov'
8
+ require 'timecop'
8
9
  SimpleCov.start
9
10
 
10
11
  Rails.backtrace_cleaner.remove_silencers!
@@ -0,0 +1,5 @@
1
+ connec_api_id: ''
2
+ connec_api_key: ''
3
+
4
+ encryption_key1: ''
5
+ encryption_key2: ''
@@ -47,7 +47,7 @@ gem 'uglifier', '>= 1.3.0'
47
47
 
48
48
  gem 'maestrano-connector-rails'
49
49
  gem 'config'
50
- # gem 'attr_encrypted', '~> 3.0.0'
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
@@ -1,6 +1,7 @@
1
1
  app_host: 'http://localhost:3001/'
2
2
 
3
- # encryption_key: 'This is a key that is 256 bits!!'
3
+ encryption_key1: 'This is a key that is 256 bits!!'
4
+ encryption_key2: 'This is a key that is 256 bits!!'
4
5
 
5
6
  default:
6
7
  api_host: 'https://maestrano.com'
@@ -1,4 +1,5 @@
1
- # encryption_key: <%= ENV['encryption_key'] %>
1
+ encryption_key1: <%= ENV['encryption_key1'] %>
2
+ encryption_key2: <%= ENV['encryption_key2'] %>
2
3
 
3
4
  # tenant config
4
5
  default:
@@ -1,6 +1,7 @@
1
1
  app_host: 'http://localhost:3001/'
2
2
 
3
- # encryption_key: 'This is a key that is 256 bits!!'
3
+ encryption_key1: 'This is a key that is 256 bits!!'
4
+ encryption_key2: 'This is a key that is 256 bits!!'
4
5
 
5
6
  default:
6
7
  environment: 'local'
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
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-07 00:00:00.000000000 Z
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