maestrano-connector-rails 2.3.2 → 2.3.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA256:
3
- metadata.gz: fe03ff785065c1f8cadca66eb2e2b82ed5fc84f5323c4869b48336d12972c85b
4
- data.tar.gz: b498996b210d55d76a64ddee0e3172b98ec59a2414865c6cc78b29cecd926057
2
+ SHA1:
3
+ metadata.gz: d68e736e0130292d4985536e944a42f6b373dad1
4
+ data.tar.gz: 47dc6757656ad1363103a289191ab8c3bb52e48a
5
5
  SHA512:
6
- metadata.gz: e4bcd12d815b164b47bcea4882499ddecfacb4ed5eb86aa140ef89aa086f98df44dd250b5cc9f32f87ac05974038c026aef2917c1294178ff75141ede6c76d1b
7
- data.tar.gz: 7118fddc3d02a5681232eeec359c16f2c500aac7456a621577d8443420d1785cd19a87c954bff5d011aa3a78ea864cd66af2b55d50a6851f830192ddf4c51ea7
6
+ metadata.gz: c267435b208139421e3022f830805875fa57bdd4017e836d5dde57c58c90d4813e34948d3382e3eb06d7d831359ab7e52b2e42223aabc4a5c882a330f2c7e38b
7
+ data.tar.gz: 24d85d8957e387213429130c571ee0f60d7697be355d6cbfba573ab9f449862ffa7ed88a57229f34b2b83368ee169729dbc3c180dded7056731fc6911b2e365c
data/CHANGELOG.md CHANGED
@@ -1,3 +1,18 @@
1
+ ## 2.3.3
2
+
3
+ * [MARLIN-244] Decorate SynchronizationController [\#176](https://github.com/maestrano/maestrano-connector-rails/pull/176)
4
+ * Rubofix [\#177](https://github.com/maestrano/maestrano-connector-rails/pull/177)
5
+ * [MNO-816] Fix regex pattern [\#175](https://github.com/maestrano/maestrano-connector-rails/pull/175)
6
+ * Spread out sync jobs [\#173](https://github.com/maestrano/maestrano-connector-rails/pull/173)
7
+
8
+ ## 2.3.2
9
+
10
+ * Update framework generators and template [\#171](https://github.com/maestrano/maestrano-connector-rails/pull/171)
11
+
12
+ ## 2.3.1
13
+
14
+ * Do not skip Connec! webhook on push_disabled (transac! compatibility) [\#170](https://github.com/maestrano/maestrano-connector-rails/pull/170)
15
+
1
16
  ## 2.3.0
2
17
 
3
18
  * Send data to Connec! even if the push/pull parameters are disabled (Transac! integration)
data/Gemfile CHANGED
@@ -1,4 +1,6 @@
1
- source 'http://rubygems.org'
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
2
4
 
3
5
  gemspec
4
6
 
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Maestrano
4
+ module Concerns
5
+ module SynchronizationsController
6
+ extend ActiveSupport::Concern
7
+
8
+ #==================================================================
9
+ # Included methods
10
+ #==================================================================
11
+ # 'included do' causes the included code to be evaluated in the
12
+ # context where it is included rather than being executed in the
13
+ # module's context
14
+ included do
15
+ end
16
+
17
+ #==================================================================
18
+ # Class methods
19
+ #==================================================================
20
+ module ClassMethods
21
+ end
22
+
23
+ #==================================================================
24
+ # Instance methods
25
+ #==================================================================
26
+ def show
27
+ tenant = params[:tenant]
28
+ uid = params[:id]
29
+ organization = Maestrano::Connector::Rails::Organization.find_by(uid: uid, tenant: tenant)
30
+ return render json: {errors: [{message: 'Organization not found', code: 404}]}, status: :not_found unless organization
31
+
32
+ status = organization_status organization
33
+
34
+ render_organization_sync(organization, status, 200)
35
+ end
36
+
37
+ def create
38
+ tenant = params[:tenant]
39
+ uid = params[:group_id]
40
+ opts = params[:opts] || {}
41
+ organization = Maestrano::Connector::Rails::Organization.find_by(uid: uid, tenant: tenant)
42
+ return render json: {errors: [{message: 'Organization not found', code: 404}]}, status: :not_found unless organization
43
+
44
+ organization.sync_enabled = organization.synchronized_entities.values.any? { |settings| settings.values.any? { |v| v } }
45
+ organization.save if organization.sync_enabled_changed?
46
+
47
+ status = organization_status(organization)
48
+
49
+ unless %w[RUNNING ENQUEUED].include?(status)
50
+ Maestrano::Connector::Rails::SynchronizationJob.perform_later(organization.id, opts.with_indifferent_access)
51
+ status = 'ENQUEUED'
52
+ end
53
+
54
+ render_organization_sync(organization, status, 201)
55
+ end
56
+
57
+ def update_metadata
58
+ tenant = params[:tenant]
59
+ uid = params[:group_id]
60
+ organization = Maestrano::Connector::Rails::Organization.find_by(uid: uid, tenant: tenant)
61
+ return render json: {errors: [{message: 'Organization not found', code: 404}]}, status: :not_found unless organization
62
+
63
+ organization.set_instance_metadata
64
+ organization.reset_synchronized_entities
65
+ render_organization_sync(organization, status, 200)
66
+ end
67
+
68
+ def toggle_sync
69
+ tenant = params[:tenant]
70
+ uid = params[:group_id]
71
+ organization = Maestrano::Connector::Rails::Organization.find_by(uid: uid, tenant: tenant)
72
+ return render json: {errors: [{message: 'Organization not found', code: 404}]}, status: :not_found unless organization
73
+
74
+ organization.toggle(:sync_enabled)
75
+ organization.save
76
+ status = organization_status organization
77
+ render_organization_sync(organization, status, 200)
78
+ end
79
+
80
+ private
81
+
82
+ def render_organization_sync(organization, status, code)
83
+ h = {
84
+ group_id: organization.uid,
85
+ sync_enabled: organization.sync_enabled,
86
+ status: status
87
+ }
88
+ last_sync = organization.synchronizations.last
89
+ if last_sync
90
+ h[:message] = last_sync.message
91
+ h[:updated_at] = last_sync.updated_at
92
+ end
93
+
94
+ render json: h, status: code
95
+ end
96
+
97
+ def organization_status(organization)
98
+ if Maestrano::Connector::Rails::SynchronizationJob.find_running_job(organization.id)
99
+ 'RUNNING'
100
+ elsif Maestrano::Connector::Rails::SynchronizationJob.find_job(organization.id)
101
+ 'ENQUEUED'
102
+ else
103
+ organization.synchronizations.last&.status || 'DISABLED'
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
@@ -9,6 +9,7 @@ class Maestrano::ConnecController < Maestrano::Rails::WebHookController
9
9
  begin
10
10
  organization = find_valid_organization(entity[:group_id], params[:tenant], entity_class_hash)
11
11
  next if organization.blank?
12
+
12
13
  Maestrano::Connector::Rails::ConnectorLogger.log('info', organization, "Processing entity from Connec! webhook, entity_name=\"#{entity_name}\", data=\"#{entity}\"")
13
14
 
14
15
  connec_client = Maestrano::Connector::Rails::ConnecHelper.get_client(organization)
@@ -1,82 +1,7 @@
1
- class Maestrano::SynchronizationsController < Maestrano::Rails::WebHookController
2
- def show
3
- tenant = params[:tenant]
4
- uid = params[:id]
5
- organization = Maestrano::Connector::Rails::Organization.find_by(uid: uid, tenant: tenant)
6
- return render json: {errors: [{message: 'Organization not found', code: 404}]}, status: :not_found unless organization
1
+ # frozen_string_literal: true
7
2
 
8
- status = organization_status organization
9
-
10
- render_organization_sync(organization, status, 200)
3
+ module Maestrano
4
+ class SynchronizationsController < Maestrano::Rails::WebHookController
5
+ include Maestrano::Concerns::SynchronizationsController
11
6
  end
12
-
13
- def create
14
- tenant = params[:tenant]
15
- uid = params[:group_id]
16
- opts = params[:opts] || {}
17
- organization = Maestrano::Connector::Rails::Organization.find_by(uid: uid, tenant: tenant)
18
- return render json: {errors: [{message: 'Organization not found', code: 404}]}, status: :not_found unless organization
19
-
20
- organization.sync_enabled = organization.synchronized_entities.values.any? { |settings| settings.values.any? { |v| v } }
21
- organization.save if organization.sync_enabled_changed?
22
-
23
- status = organization_status(organization)
24
-
25
- unless %w[RUNNING ENQUEUED].include?(status)
26
- Maestrano::Connector::Rails::SynchronizationJob.perform_later(organization.id, opts.with_indifferent_access)
27
- status = 'ENQUEUED'
28
- end
29
-
30
- render_organization_sync(organization, status, 201)
31
- end
32
-
33
- def update_metadata
34
- tenant = params[:tenant]
35
- uid = params[:group_id]
36
- organization = Maestrano::Connector::Rails::Organization.find_by(uid: uid, tenant: tenant)
37
- return render json: {errors: [{message: 'Organization not found', code: 404}]}, status: :not_found unless organization
38
-
39
- organization.set_instance_metadata
40
- organization.reset_synchronized_entities
41
- render_organization_sync(organization, status, 200)
42
- end
43
-
44
- def toggle_sync
45
- tenant = params[:tenant]
46
- uid = params[:group_id]
47
- organization = Maestrano::Connector::Rails::Organization.find_by(uid: uid, tenant: tenant)
48
- return render json: {errors: [{message: 'Organization not found', code: 404}]}, status: :not_found unless organization
49
-
50
- organization.toggle(:sync_enabled)
51
- organization.save
52
- status = organization_status organization
53
- render_organization_sync(organization, status, 200)
54
- end
55
-
56
- private
57
-
58
- def render_organization_sync(organization, status, code)
59
- h = {
60
- group_id: organization.uid,
61
- sync_enabled: organization.sync_enabled,
62
- status: status
63
- }
64
- last_sync = organization.synchronizations.last
65
- if last_sync
66
- h[:message] = last_sync.message
67
- h[:updated_at] = last_sync.updated_at
68
- end
69
-
70
- render json: h, status: code
71
- end
72
-
73
- def organization_status(organization)
74
- if Maestrano::Connector::Rails::SynchronizationJob.find_running_job(organization.id)
75
- 'RUNNING'
76
- elsif Maestrano::Connector::Rails::SynchronizationJob.find_job(organization.id)
77
- 'ENQUEUED'
78
- else
79
- organization.synchronizations.last&.status || 'DISABLED'
80
- end
81
- end
82
7
  end
@@ -4,9 +4,15 @@ 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.not(oauth_provider: nil, encrypted_oauth_token: nil).each do |o|
8
- next unless [true, 1].include?(o.sync_enabled)
9
- Maestrano::Connector::Rails::SynchronizationJob.perform_later(o.id, {})
7
+ active_organizations = Maestrano::Connector::Rails::Organization
8
+ .where.not(oauth_provider: nil, encrypted_oauth_token: nil)
9
+ .select { |o| [true, 1].include?(o.sync_enabled) }
10
+
11
+ return true if active_organizations.count.zero?
12
+
13
+ time_span_seconds = (3600 / active_organizations.count).to_i
14
+ active_organizations.each_with_index do |organization, i|
15
+ Maestrano::Connector::Rails::SynchronizationJob.set(wait: time_span_seconds * i).perform_later(organization.id, {})
10
16
  end
11
17
  end
12
18
  end
@@ -14,10 +14,10 @@ module Maestrano::Connector::Rails::Concerns::SynchronizationJob
14
14
  queue = Sidekiq::Queue.new(:default)
15
15
  queue.find do |job|
16
16
  job_organization_id = begin
17
- job.item['args'][0]['arguments'].first
18
- rescue
19
- false
20
- end
17
+ job.item['args'][0]['arguments'].first
18
+ rescue
19
+ false
20
+ end
21
21
  organization_id == job_organization_id
22
22
  end
23
23
  end
@@ -25,10 +25,10 @@ module Maestrano::Connector::Rails::Concerns::SynchronizationJob
25
25
  def find_running_job(organization_id)
26
26
  Sidekiq::Workers.new.find do |_, _, work|
27
27
  job_organization_id = begin
28
- work['payload']['args'][0]['arguments'].first
29
- rescue
30
- false
31
- end
28
+ work['payload']['args'][0]['arguments'].first
29
+ rescue
30
+ false
31
+ end
32
32
  work['queue'] == 'default' && organization_id == job_organization_id
33
33
  end
34
34
  rescue
@@ -75,6 +75,7 @@ module Maestrano::Connector::Rails::Concerns::SynchronizationJob
75
75
  Maestrano::Connector::Rails::ConnectorLogger.log('info', organization, 'First synchronization ever. Doing two half syncs to allow smart merging to work its magic.')
76
76
  organization.synchronized_entities.each do |entity, settings|
77
77
  next unless settings[:can_push_to_connec] || settings[:can_push_to_external]
78
+
78
79
  Maestrano::Connector::Rails::ConnectorLogger.log('info', organization, "First synchronization ever. Doing half sync from external for #{entity}.")
79
80
  first_sync_entity(entity.to_s, organization, connec_client, external_client, last_synchronization_date, opts, true)
80
81
  Maestrano::Connector::Rails::ConnectorLogger.log('info', organization, "First synchronization ever. Doing half sync from Connec! for #{entity}.")
@@ -90,6 +91,7 @@ module Maestrano::Connector::Rails::Concerns::SynchronizationJob
90
91
  else
91
92
  organization.synchronized_entities.each do |entity, settings|
92
93
  next unless settings[:can_push_to_connec] || settings[:can_push_to_external]
94
+
93
95
  sync_entity(entity.to_s, organization, connec_client, external_client, last_synchronization_date, opts)
94
96
  end
95
97
  end
@@ -136,6 +138,7 @@ module Maestrano::Connector::Rails::Concerns::SynchronizationJob
136
138
  # We're comparing the first record to check that it is different
137
139
  first_record = Digest::MD5.hexdigest(perform_hash[:first].to_s)
138
140
  break if last_first_record && first_record == last_first_record
141
+
139
142
  last_first_record = first_record
140
143
 
141
144
  skip += limit
@@ -8,6 +8,7 @@ module Maestrano::Connector::Rails::Concerns::UpdateConfigurationJob
8
8
 
9
9
  def perform
10
10
  return if ENV['SKIP_CONFIGURATION']
11
+
11
12
  Maestrano.reset!
12
13
  Maestrano.auto_configure
13
14
  rescue StandardError => e
@@ -24,6 +24,7 @@ module Maestrano::Connector::Rails::Concerns::ComplexEntity
24
24
 
25
25
  def formatted_entities_names(names)
26
26
  return names.with_indifferent_access if names.is_a?(Hash)
27
+
27
28
  names.index_by { |name| name }.with_indifferent_access
28
29
  end
29
30
 
@@ -44,6 +45,7 @@ module Maestrano::Connector::Rails::Concerns::ComplexEntity
44
45
  def public_name(formatted_names)
45
46
  names = formatted_names.keys.map(&:pluralize)
46
47
  return names.first.humanize if names.size == 1
48
+
47
49
  (names[0..-2].join(', ') + " and #{names.last}").humanize
48
50
  end
49
51
  end
@@ -119,6 +119,7 @@ module Maestrano::Connector::Rails::Concerns::ConnecHelper
119
119
  # Unfold the id
120
120
  if array_of_refs.empty? && field
121
121
  return entity.delete(ref) if field.is_a?(String) # ~retro-compatibility to ease transition aroud Connec! idmaps rework. Should be removed eventually.
122
+
122
123
  id_hash = field.find { |id| id[:provider] == organization.oauth_provider && id[:realm] == organization.oauth_uid }
123
124
  if id_hash
124
125
  entity[ref] = id_hash['id']
@@ -134,6 +135,7 @@ module Maestrano::Connector::Rails::Concerns::ConnecHelper
134
135
  # Follow embedment path
135
136
  else
136
137
  return true if field.blank?
138
+
137
139
  case field
138
140
  when Array
139
141
  bool = true
@@ -151,6 +153,7 @@ module Maestrano::Connector::Rails::Concerns::ConnecHelper
151
153
  # References can either be an array (only record references), or a hash
152
154
  def format_references(references)
153
155
  return {record_references: references, id_references: []} if references.is_a?(Array)
156
+
154
157
  references[:record_references] ||= []
155
158
  references[:id_references] ||= []
156
159
  references
@@ -173,6 +176,7 @@ module Maestrano::Connector::Rails::Concerns::ConnecHelper
173
176
  # Recursive method for filtering connec entities
174
177
  def filter_connec_entity_for_id_refs_helper(entity_hash, tree)
175
178
  return if tree.empty?
179
+
176
180
  entity_hash.slice!(*tree.keys)
177
181
 
178
182
  tree.each do |key, children|
@@ -234,7 +234,7 @@ module Maestrano::Connector::Rails::Concerns::Entity
234
234
  # Fetch subsequent pages
235
235
  while response_hash['pagination'] && response_hash['pagination']['next']
236
236
  # ugly way to convert https://api-connec/api/v2/group_id/organizations?next_page_params to /organizations?next_page_params
237
- next_page = response_hash['pagination']['next'].gsub(/^(.*)\/#{self.class.normalized_connec_entity_name}/, self.class.normalized_connec_entity_name)
237
+ next_page = response_hash['pagination']['next'].gsub(/\A(.*)\/#{self.class.normalized_connec_entity_name}/, self.class.normalized_connec_entity_name)
238
238
 
239
239
  response_hash = fetch_connec(next_page)
240
240
  entities.concat response_hash[self.class.normalized_connec_entity_name]
@@ -273,6 +273,7 @@ module Maestrano::Connector::Rails::Concerns::Entity
273
273
  mapped_external_entities_with_idmaps.each do |mapped_external_entity_with_idmap|
274
274
  id_map = mapped_external_entity_with_idmap[:idmap]
275
275
  next unless id_map&.metadata&.dig(:ignore_currency_update)
276
+
276
277
  self.class.currency_check_fields.each do |field|
277
278
  mapped_external_entity_with_idmap[:entity].delete(field)
278
279
  end
@@ -302,6 +303,7 @@ module Maestrano::Connector::Rails::Concerns::Entity
302
303
  # Wrapper to process options and limitations
303
304
  def get_external_entities_wrapper(last_synchronization_date = nil, entity_name = self.class.external_entity_name)
304
305
  return [] if @opts[:__skip_external] || !self.class.can_read_external?
306
+
305
307
  get_external_entities(entity_name, last_synchronization_date)
306
308
  end
307
309
 
@@ -367,6 +369,7 @@ module Maestrano::Connector::Rails::Concerns::Entity
367
369
  # Update
368
370
  else
369
371
  return nil unless self.class.can_update_external?
372
+
370
373
  external_hash = update_external_entity(mapped_connec_entity, idmap.external_id, external_entity_name)
371
374
 
372
375
  completed_hash = map_and_complete_hash_with_connec_ids(external_hash, external_entity_name, id_refs_only_connec_entity)
@@ -479,6 +482,7 @@ module Maestrano::Connector::Rails::Concerns::Entity
479
482
  response = @connec_client.batch(batch_request)
480
483
  Maestrano::Connector::Rails::ConnectorLogger.log('debug', @organization, "Received batch response from Connec! for #{self.class.normalize_connec_entity_name(connec_entity_name)}: #{response}")
481
484
  raise "No data received from Connec! when trying to send batch request #{log_info} for #{self.class.connec_entity_name.pluralize}" unless response && response.body.present?
485
+
482
486
  response = JSON.parse(response.body)
483
487
 
484
488
  # Parse batch response
@@ -114,6 +114,7 @@ module Maestrano::Connector::Rails::Concerns::Organization
114
114
  def enable_historical_data(enabled)
115
115
  # Historical data sharing cannot be unset
116
116
  return if historical_data
117
+
117
118
  if enabled
118
119
  self.date_filtering_limit = nil
119
120
  self.historical_data = true
@@ -12,11 +12,13 @@ module Maestrano::Connector::Rails::Concerns::SubEntityBase
12
12
 
13
13
  def external_entity_name
14
14
  return entity_name if external?
15
+
15
16
  raise 'Forbidden call: cannot call external_entity_name for a connec entity'
16
17
  end
17
18
 
18
19
  def connec_entity_name
19
20
  return entity_name unless external?
21
+
20
22
  raise 'Forbidden call: cannot call connec_entity_name for an external entity'
21
23
  end
22
24
 
@@ -16,6 +16,7 @@ class Maestrano::Connector::Rails::ApplicationPolicy
16
16
  def initialize(user, record)
17
17
  # Closed system: must be logged in to do anything
18
18
  raise Pundit::NotAuthorizedError, 'must be logged in' unless user
19
+
19
20
  @user = user
20
21
  @record = record
21
22
  end
@@ -16,6 +16,7 @@ module Maestrano
16
16
  def self.all_filters
17
17
  # Skipping if there is no tables as calling columns_hash in attribute_type is causing issue
18
18
  return unless tables_exists?
19
+
19
20
  _attributes.keys.each do |attribute|
20
21
  type = attribute_type(attribute)
21
22
  if type == :boolean
@@ -34,6 +35,7 @@ module Maestrano
34
35
  # iterating through all the api operator and adding them as custom filter
35
36
  # name.gt, name.like etc...
36
37
  next unless _model_class
38
+
37
39
  field = "#{_model_class.table_name}.#{key}"
38
40
 
39
41
  API_SQL_OPERATOR_MAPPING.each do |api_operator, sql_operator|
@@ -15,6 +15,7 @@ module Maestrano
15
15
  @model.tenant = context[:client]
16
16
  super
17
17
  return unless org_uid == context.dig(:params, :org_uid)
18
+
18
19
  org = Maestrano::Connector::Rails::Organization.find_by(org_uid: org_uid)
19
20
  org.add_member(@model) unless !org || org.member?(@model)
20
21
  end
@@ -1,7 +1,7 @@
1
1
  module Maestrano
2
2
  module Connector
3
3
  module Rails
4
- VERSION = '2.3.2'.freeze
4
+ VERSION = '2.3.3'.freeze
5
5
  end
6
6
  end
7
7
  end
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: 2.3.2
4
+ version: 2.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maestrano
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-04-26 00:00:00.000000000 Z
11
+ date: 2018-09-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -435,6 +435,7 @@ files:
435
435
  - app/controllers/maestrano/api/users_controller.rb
436
436
  - app/controllers/maestrano/application_controller.rb
437
437
  - app/controllers/maestrano/auth/saml_controller.rb
438
+ - app/controllers/maestrano/concerns/synchronizations_controller.rb
438
439
  - app/controllers/maestrano/connec_controller.rb
439
440
  - app/controllers/maestrano/dependancies_controller.rb
440
441
  - app/controllers/maestrano/sessions_controller.rb
@@ -563,7 +564,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
563
564
  version: '0'
564
565
  requirements: []
565
566
  rubyforge_project:
566
- rubygems_version: 2.7.6
567
+ rubygems_version: 2.6.14
567
568
  signing_key:
568
569
  specification_version: 4
569
570
  summary: Rails framework to build connector with Maestrano