maestrano-connector-rails 2.0.2.pre.RC9 → 2.0.2.pre.RC10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/Rakefile +1 -1
- data/app/jobs/maestrano/connector/rails/concerns/synchronization_job.rb +153 -0
- data/app/jobs/maestrano/connector/rails/synchronization_job.rb +1 -144
- data/app/models/maestrano/connector/rails/concerns/connector_logger.rb +1 -1
- data/app/models/maestrano/connector/rails/concerns/entity.rb +3 -3
- data/app/models/maestrano/connector/rails/concerns/id_map.rb +8 -0
- data/app/models/maestrano/connector/rails/concerns/organization.rb +161 -0
- data/app/models/maestrano/connector/rails/concerns/synchronization.rb +54 -0
- data/app/models/maestrano/connector/rails/concerns/user.rb +27 -0
- data/app/models/maestrano/connector/rails/id_map.rb +1 -2
- data/app/models/maestrano/connector/rails/organization.rb +1 -154
- data/app/models/maestrano/connector/rails/synchronization.rb +1 -46
- data/app/models/maestrano/connector/rails/user.rb +1 -21
- data/config/routes.rb +2 -2
- data/lib/generators/connector/install_generator.rb +5 -0
- data/lib/generators/connector/templates/home_controller.rb +1 -1
- data/lib/generators/connector/templates/home_controller_spec.rb +20 -12
- data/lib/generators/connector/templates/home_index.haml +1 -7
- data/lib/generators/connector/templates/layouts.haml +2 -2
- data/lib/generators/connector/templates/logos/to_connec.png +0 -0
- data/lib/generators/connector/templates/logos/to_external.png +0 -0
- data/lib/maestrano/connector/rails/version.rb +1 -1
- data/maestrano-connector-rails.gemspec +1 -0
- metadata +24 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 65e017e72e894da3e1fadf4eda7d24580fe90176
|
4
|
+
data.tar.gz: 09168f2321092da1b57490468516225190cd9e64
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cb5e4891f48db210ddf0a2881fe3cffaabe1850b42eebfb0988f02f1ef49a13f93984ba4f59b7bed1c6a26a740bc08023e173c25dfa3f4f3661aa01514cc50db
|
7
|
+
data.tar.gz: baea5af0aca2aac129786700ea1abf1df7a2d1969821cd54f97185c22d3ad338ead03a75d6d13e57915bc11ab2f2d63a9115949decbce5b57b4d21a3c4364630
|
data/.gitignore
CHANGED
data/Rakefile
CHANGED
@@ -0,0 +1,153 @@
|
|
1
|
+
module Maestrano::Connector::Rails::Concerns::SynchronizationJob
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
included do
|
5
|
+
queue_as :default
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def enqueued?(organization_id)
|
10
|
+
Maestrano::Connector::Rails::SynchronizationJob.find_job(organization_id).present? || Maestrano::Connector::Rails::SynchronizationJob.find_running_job(organization_id).present?
|
11
|
+
end
|
12
|
+
|
13
|
+
def find_job(organization_id)
|
14
|
+
queue = Sidekiq::Queue.new(:default)
|
15
|
+
queue.find do |job|
|
16
|
+
organization_id == job.item['args'][0]['arguments'].first
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def find_running_job(organization_id)
|
21
|
+
Sidekiq::Workers.new.find do |_, _, work|
|
22
|
+
work['queue'] == 'default' && work['payload']['args'][0]['arguments'].first == organization_id
|
23
|
+
end
|
24
|
+
rescue
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Supported options:
|
30
|
+
# * :forced => true synchronization has been triggered manually
|
31
|
+
# * :only_entities => [person, tasks_list]
|
32
|
+
# * :full_sync => true synchronization is performed without date filtering
|
33
|
+
# * :connec_preemption => true|false : preemption is always|never given to connec in case of conflict (if not set, the most recently updated entity is kept)
|
34
|
+
def perform(organization_id, opts = {})
|
35
|
+
organization = Maestrano::Connector::Rails::Organization.find(organization_id)
|
36
|
+
return unless organization&.sync_enabled
|
37
|
+
|
38
|
+
# Check if previous synchronization is still running
|
39
|
+
if Maestrano::Connector::Rails::Synchronization.where(organization_id: organization.id, status: 'RUNNING').where(created_at: (30.minutes.ago..Time.now.utc)).exists?
|
40
|
+
Maestrano::Connector::Rails::ConnectorLogger.log('info', organization, 'Synchronization skipped: Previous synchronization is still running')
|
41
|
+
return
|
42
|
+
end
|
43
|
+
|
44
|
+
# Check if recovery mode: last 3 synchronizations have failed
|
45
|
+
if !opts[:forced] && organization.last_three_synchronizations_failed? \
|
46
|
+
&& organization.synchronizations.order(created_at: :desc).limit(1).first.updated_at > 1.day.ago
|
47
|
+
Maestrano::Connector::Rails::ConnectorLogger.log('info', organization, 'Synchronization skipped: Recovery mode (three previous synchronizations have failed)')
|
48
|
+
return
|
49
|
+
end
|
50
|
+
|
51
|
+
# Trigger synchronization
|
52
|
+
Maestrano::Connector::Rails::ConnectorLogger.log('info', organization, "Start synchronization, opts=#{opts}")
|
53
|
+
current_synchronization = Maestrano::Connector::Rails::Synchronization.create_running(organization)
|
54
|
+
|
55
|
+
begin
|
56
|
+
last_synchronization = organization.last_successful_synchronization
|
57
|
+
last_synchronization_date = organization.last_synchronization_date
|
58
|
+
connec_client = Maestrano::Connector::Rails::ConnecHelper.get_client(organization)
|
59
|
+
external_client = Maestrano::Connector::Rails::External.get_client(organization)
|
60
|
+
|
61
|
+
# First synchronization should be from external to Connec! only to let the smart merging works
|
62
|
+
# We do a doube sync: only from external, then only from connec!
|
63
|
+
# We also do batched sync as the first one can be quite huge
|
64
|
+
if last_synchronization.nil?
|
65
|
+
Maestrano::Connector::Rails::ConnectorLogger.log('info', organization, 'First synchronization ever. Doing two half syncs to allow smart merging to work its magic.')
|
66
|
+
organization.synchronized_entities.each do |entity, settings|
|
67
|
+
next unless settings[:can_push_to_connec] || settings[:can_push_to_external]
|
68
|
+
Maestrano::Connector::Rails::ConnectorLogger.log('info', organization, "First synchronization ever. Doing half sync from external for #{entity}.")
|
69
|
+
first_sync_entity(entity.to_s, organization, connec_client, external_client, last_synchronization_date, opts, true)
|
70
|
+
Maestrano::Connector::Rails::ConnectorLogger.log('info', organization, "First synchronization ever. Doing half sync from Connec! for #{entity}.")
|
71
|
+
first_sync_entity(entity.to_s, organization, connec_client, external_client, last_synchronization_date, opts, false)
|
72
|
+
end
|
73
|
+
elsif opts[:only_entities]
|
74
|
+
Maestrano::Connector::Rails::ConnectorLogger.log('info', organization, "Synchronization is partial and will synchronize only #{opts[:only_entities].join(' ')}")
|
75
|
+
# The synchronization is marked as partial and will not be considered as the last-synchronization for the next sync
|
76
|
+
current_synchronization.mark_as_partial
|
77
|
+
opts[:only_entities].each do |entity|
|
78
|
+
sync_entity(entity, organization, connec_client, external_client, last_synchronization_date, opts)
|
79
|
+
end
|
80
|
+
else
|
81
|
+
organization.synchronized_entities.each do |entity, settings|
|
82
|
+
next unless settings[:can_push_to_connec] || settings[:can_push_to_external]
|
83
|
+
sync_entity(entity.to_s, organization, connec_client, external_client, last_synchronization_date, opts)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
Maestrano::Connector::Rails::ConnectorLogger.log('info', organization, "Finished synchronization, organization=#{organization.uid}, status=success")
|
88
|
+
current_synchronization.mark_as_success
|
89
|
+
rescue => e
|
90
|
+
Maestrano::Connector::Rails::ConnectorLogger.log('info', organization, "Finished synchronization, organization=#{organization.uid}, status=error, message=#{e.message} backtrace=#{e.backtrace.join("\n\t")}")
|
91
|
+
current_synchronization.mark_as_error(e.message)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def sync_entity(entity_name, organization, connec_client, external_client, last_synchronization_date, opts)
|
96
|
+
entity_instance = instanciate_entity(entity_name, organization, connec_client, external_client, opts)
|
97
|
+
|
98
|
+
perform_sync(entity_instance, last_synchronization_date)
|
99
|
+
end
|
100
|
+
|
101
|
+
# Does a batched sync on either external or connec!
|
102
|
+
def first_sync_entity(entity_name, organization, connec_client, external_client, last_synchronization_date, opts, external = true)
|
103
|
+
limit = Settings.first_sync_batch_size || 50
|
104
|
+
skip = 0
|
105
|
+
entities_count = limit
|
106
|
+
last_first_record = nil
|
107
|
+
|
108
|
+
h = {__limit: limit}
|
109
|
+
external ? h[:__skip_connec] = true : h[:__skip_external] = true
|
110
|
+
entity_instance = instanciate_entity(entity_name, organization, connec_client, external_client, opts.merge(h))
|
111
|
+
|
112
|
+
# IF entities_count > limit
|
113
|
+
# This first sync feature is probably not implemented in the connector
|
114
|
+
# because it fetched more than the expected number of entities
|
115
|
+
# No need to fetch it a second Time
|
116
|
+
# ELSIF entities_count < limit
|
117
|
+
# No more entities to fetch
|
118
|
+
while entities_count == limit
|
119
|
+
entity_instance.opts_merge!(__skip: skip)
|
120
|
+
|
121
|
+
perform_hash = perform_sync(entity_instance, last_synchronization_date, external)
|
122
|
+
entities_count = perform_hash[:count]
|
123
|
+
|
124
|
+
# Safety: if the connector does not implement batched calls but has exactly limit entities
|
125
|
+
# There is a risk of infinite loop
|
126
|
+
# We're comparing the first record to check that it is different
|
127
|
+
first_record = Digest::MD5.hexdigest(perform_hash[:first].to_s)
|
128
|
+
break if last_first_record && first_record == last_first_record
|
129
|
+
last_first_record = first_record
|
130
|
+
|
131
|
+
skip += limit
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
private
|
136
|
+
|
137
|
+
def instanciate_entity(entity_name, organization, connec_client, external_client, opts)
|
138
|
+
"Entities::#{entity_name.titleize.split.join}".constantize.new(organization, connec_client, external_client, opts.dup)
|
139
|
+
end
|
140
|
+
|
141
|
+
# Perform the sync and return the entities_count for either external or connec
|
142
|
+
def perform_sync(entity_instance, last_synchronization_date, external = true)
|
143
|
+
entity_instance.before_sync(last_synchronization_date)
|
144
|
+
external_entities = entity_instance.get_external_entities_wrapper(last_synchronization_date)
|
145
|
+
connec_entities = entity_instance.get_connec_entities(last_synchronization_date)
|
146
|
+
mapped_entities = entity_instance.consolidate_and_map_data(connec_entities, external_entities)
|
147
|
+
entity_instance.push_entities_to_external(mapped_entities[:connec_entities])
|
148
|
+
entity_instance.push_entities_to_connec(mapped_entities[:external_entities])
|
149
|
+
entity_instance.after_sync(last_synchronization_date)
|
150
|
+
|
151
|
+
entity_instance.class.count_and_first(external ? external_entities : connec_entities)
|
152
|
+
end
|
153
|
+
end
|
@@ -1,148 +1,5 @@
|
|
1
1
|
module Maestrano::Connector::Rails
|
2
2
|
class SynchronizationJob < ::ActiveJob::Base
|
3
|
-
|
4
|
-
|
5
|
-
# Supported options:
|
6
|
-
# * :forced => true synchronization has been triggered manually
|
7
|
-
# * :only_entities => [person, tasks_list]
|
8
|
-
# * :full_sync => true synchronization is performed without date filtering
|
9
|
-
# * :connec_preemption => true|false : preemption is always|never given to connec in case of conflict (if not set, the most recently updated entity is kept)
|
10
|
-
def perform(organization_id, opts = {})
|
11
|
-
organization = Maestrano::Connector::Rails::Organization.find(organization_id)
|
12
|
-
return unless organization&.sync_enabled
|
13
|
-
# Check if previous synchronization is still running
|
14
|
-
if Synchronization.where(organization_id: organization.id, status: 'RUNNING').where(created_at: (30.minutes.ago..Time.now)).exists?
|
15
|
-
ConnectorLogger.log('info', organization, 'Synchronization skipped: Previous synchronization is still running')
|
16
|
-
return
|
17
|
-
end
|
18
|
-
|
19
|
-
# Check if recovery mode: last 3 synchronizations have failed
|
20
|
-
if !opts[:forced] && organization.last_three_synchronizations_failed? \
|
21
|
-
&& organization.synchronizations.order(created_at: :desc).limit(1).first.updated_at > 1.day.ago
|
22
|
-
ConnectorLogger.log('info', organization, 'Synchronization skipped: Recovery mode (three previous synchronizations have failed)')
|
23
|
-
return
|
24
|
-
end
|
25
|
-
|
26
|
-
# Trigger synchronization
|
27
|
-
ConnectorLogger.log('info', organization, "Start synchronization, opts=#{opts}")
|
28
|
-
current_synchronization = Synchronization.create_running(organization)
|
29
|
-
|
30
|
-
begin
|
31
|
-
last_synchronization = organization.last_successful_synchronization
|
32
|
-
last_synchronization_date = organization.last_synchronization_date
|
33
|
-
connec_client = ConnecHelper.get_client(organization)
|
34
|
-
external_client = External.get_client(organization)
|
35
|
-
|
36
|
-
# First synchronization should be from external to Connec! only to let the smart merging works
|
37
|
-
# We do a doube sync: only from external, then only from connec!
|
38
|
-
# We also do batched sync as the first one can be quite huge
|
39
|
-
if last_synchronization.nil?
|
40
|
-
ConnectorLogger.log('info', organization, 'First synchronization ever. Doing two half syncs to allow smart merging to work its magic.')
|
41
|
-
organization.synchronized_entities.each do |entity, settings|
|
42
|
-
next unless settings[:can_push_to_connec] || settings[:can_push_to_external]
|
43
|
-
ConnectorLogger.log('info', organization, "First synchronization ever. Doing half sync from external for #{entity}.")
|
44
|
-
first_sync_entity(entity.to_s, organization, connec_client, external_client, last_synchronization_date, opts, true)
|
45
|
-
ConnectorLogger.log('info', organization, "First synchronization ever. Doing half sync from Connec! for #{entity}.")
|
46
|
-
first_sync_entity(entity.to_s, organization, connec_client, external_client, last_synchronization_date, opts, false)
|
47
|
-
end
|
48
|
-
elsif opts[:only_entities]
|
49
|
-
ConnectorLogger.log('info', organization, "Synchronization is partial and will synchronize only #{opts[:only_entities].join(' ')}")
|
50
|
-
# The synchronization is marked as partial and will not be considered as the last-synchronization for the next sync
|
51
|
-
current_synchronization.set_partial
|
52
|
-
opts[:only_entities].each do |entity|
|
53
|
-
sync_entity(entity, organization, connec_client, external_client, last_synchronization_date, opts)
|
54
|
-
end
|
55
|
-
else
|
56
|
-
organization.synchronized_entities.each do |entity, settings|
|
57
|
-
next unless settings[:can_push_to_connec] || settings[:can_push_to_external]
|
58
|
-
sync_entity(entity.to_s, organization, connec_client, external_client, last_synchronization_date, opts)
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
ConnectorLogger.log('info', organization, "Finished synchronization, organization=#{organization.uid}, status=success")
|
63
|
-
current_synchronization.set_success
|
64
|
-
rescue => e
|
65
|
-
ConnectorLogger.log('info', organization, "Finished synchronization, organization=#{organization.uid}, status=error, message=#{e.message} backtrace=#{e.backtrace.join("\n\t")}")
|
66
|
-
current_synchronization.set_error(e.message)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def sync_entity(entity_name, organization, connec_client, external_client, last_synchronization_date, opts)
|
71
|
-
entity_instance = instanciate_entity(entity_name, organization, connec_client, external_client, opts)
|
72
|
-
|
73
|
-
perform_sync(entity_instance, last_synchronization_date)
|
74
|
-
end
|
75
|
-
|
76
|
-
# Does a batched sync on either external or connec!
|
77
|
-
def first_sync_entity(entity_name, organization, connec_client, external_client, last_synchronization_date, opts, external = true)
|
78
|
-
limit = Settings.first_sync_batch_size || 50
|
79
|
-
skip = 0
|
80
|
-
entities_count = limit
|
81
|
-
last_first_record = nil
|
82
|
-
|
83
|
-
h = {__limit: limit}
|
84
|
-
external ? h[:__skip_connec] = true : h[:__skip_external] = true
|
85
|
-
entity_instance = instanciate_entity(entity_name, organization, connec_client, external_client, opts.merge(h))
|
86
|
-
|
87
|
-
# IF entities_count > limit
|
88
|
-
# This first sync feature is probably not implemented in the connector
|
89
|
-
# because it fetched more than the expected number of entities
|
90
|
-
# No need to fetch it a second Time
|
91
|
-
# ELSIF entities_count < limit
|
92
|
-
# No more entities to fetch
|
93
|
-
while entities_count == limit
|
94
|
-
entity_instance.opts_merge!(__skip: skip)
|
95
|
-
|
96
|
-
perform_hash = perform_sync(entity_instance, last_synchronization_date, external)
|
97
|
-
entities_count = perform_hash[:count]
|
98
|
-
|
99
|
-
# Safety: if the connector does not implement batched calls but has exactly limit entities
|
100
|
-
# There is a risk of infinite loop
|
101
|
-
# We're comparing the first record to check that it is different
|
102
|
-
first_record = Digest::MD5.hexdigest(perform_hash[:first].to_s)
|
103
|
-
break if last_first_record && first_record == last_first_record
|
104
|
-
last_first_record = first_record
|
105
|
-
|
106
|
-
skip += limit
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
def self.enqueued?(organization_id)
|
111
|
-
SynchronizationJob.find_job(organization_id).present? || SynchronizationJob.find_running_job(organization_id).present?
|
112
|
-
end
|
113
|
-
|
114
|
-
def self.find_job(organization_id)
|
115
|
-
queue = Sidekiq::Queue.new(:default)
|
116
|
-
queue.find do |job|
|
117
|
-
organization_id == job.item['args'][0]['arguments'].first
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
def self.find_running_job(organization_id)
|
122
|
-
Sidekiq::Workers.new.find do |_, _, work|
|
123
|
-
work['queue'] == 'default' && work['payload']['args'][0]['arguments'].first == organization_id
|
124
|
-
end
|
125
|
-
rescue
|
126
|
-
nil
|
127
|
-
end
|
128
|
-
|
129
|
-
private
|
130
|
-
|
131
|
-
def instanciate_entity(entity_name, organization, connec_client, external_client, opts)
|
132
|
-
"Entities::#{entity_name.titleize.split.join}".constantize.new(organization, connec_client, external_client, opts.dup)
|
133
|
-
end
|
134
|
-
|
135
|
-
# Perform the sync and return the entities_count for either external or connec
|
136
|
-
def perform_sync(entity_instance, last_synchronization_date, external = true)
|
137
|
-
entity_instance.before_sync(last_synchronization_date)
|
138
|
-
external_entities = entity_instance.get_external_entities_wrapper(last_synchronization_date)
|
139
|
-
connec_entities = entity_instance.get_connec_entities(last_synchronization_date)
|
140
|
-
mapped_entities = entity_instance.consolidate_and_map_data(connec_entities, external_entities)
|
141
|
-
entity_instance.push_entities_to_external(mapped_entities[:connec_entities])
|
142
|
-
entity_instance.push_entities_to_connec(mapped_entities[:external_entities])
|
143
|
-
entity_instance.after_sync(last_synchronization_date)
|
144
|
-
|
145
|
-
entity_instance.class.count_and_first(external ? external_entities : connec_entities)
|
146
|
-
end
|
3
|
+
include Maestrano::Connector::Rails::Concerns::SynchronizationJob
|
147
4
|
end
|
148
5
|
end
|
@@ -4,7 +4,7 @@ module Maestrano::Connector::Rails::Concerns::ConnectorLogger
|
|
4
4
|
module ClassMethods
|
5
5
|
def log(level, organization, msg, params = {})
|
6
6
|
line = "uid=\"#{organization&.uid}\", org_uid=\"#{organization&.org_uid}\", tenant=\"#{organization&.tenant}\""
|
7
|
-
line = "#{line}, #{params.map { |k, v| "#{k}=\"#{v}\"" }.join(', ')}"
|
7
|
+
line = "#{line}, #{params.map { |k, v| "#{k}=\"#{v}\"" }.join(', ')}" if params.present?
|
8
8
|
Rails.logger.method(level).call("#{line}, message=\"#{msg}\"")
|
9
9
|
end
|
10
10
|
end
|
@@ -263,7 +263,7 @@ module Maestrano::Connector::Rails::Concerns::Entity
|
|
263
263
|
|
264
264
|
# As we're doing only POST, we use the idmaps to filter out updates
|
265
265
|
unless self.class.can_update_connec?
|
266
|
-
mapped_external_entities_with_idmaps.
|
266
|
+
mapped_external_entities_with_idmaps.reject! { |mapped_external_entity_with_idmap| mapped_external_entity_with_idmap[:idmap].connec_id }
|
267
267
|
end
|
268
268
|
|
269
269
|
if self.class.currency_check_fields
|
@@ -472,7 +472,7 @@ module Maestrano::Connector::Rails::Concerns::Entity
|
|
472
472
|
Maestrano::Connector::Rails::ConnectorLogger.log('info', @organization, "Sending batch request to Connec! #{log_info} for #{self.class.normalize_connec_entity_name(connec_entity_name)}. Batch_request_size: #{batch_request[:ops].size}. Call_number: #{(start / request_per_call) + 1}")
|
473
473
|
response = @connec_client.batch(batch_request)
|
474
474
|
Maestrano::Connector::Rails::ConnectorLogger.log('debug', @organization, "Received batch response from Connec! for #{self.class.normalize_connec_entity_name(connec_entity_name)}: #{response}")
|
475
|
-
raise "No data received from Connec! when trying to send batch request #{log_info} for #{self.class.connec_entity_name.pluralize}" unless response &&
|
475
|
+
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?
|
476
476
|
response = JSON.parse(response.body)
|
477
477
|
|
478
478
|
# Parse batch response
|
@@ -497,7 +497,7 @@ module Maestrano::Connector::Rails::Concerns::Entity
|
|
497
497
|
Maestrano::Connector::Rails::ConnectorLogger.log('debug', @organization, "Fetching data from connec entity=#{self.class.connec_entity_name}, url=#{uri}")
|
498
498
|
response = @connec_client.get(uri)
|
499
499
|
|
500
|
-
raise "No data received from Connec! when trying to fetch #{self.class.normalized_connec_entity_name}" unless response &&
|
500
|
+
raise "No data received from Connec! when trying to fetch #{self.class.normalized_connec_entity_name}" unless response && response.body.present?
|
501
501
|
|
502
502
|
response_hash = JSON.parse(response.body)
|
503
503
|
Maestrano::Connector::Rails::ConnectorLogger.log('debug', @organization, "Received response for entity=#{self.class.connec_entity_name}, response=#{response_hash}")
|
@@ -0,0 +1,161 @@
|
|
1
|
+
module Maestrano::Connector::Rails::Concerns::Organization
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
included do
|
5
|
+
# Enable Maestrano for this group
|
6
|
+
maestrano_group_via :provider, :uid, :tenant do |group, maestrano|
|
7
|
+
group.name = (maestrano.name.blank? ? 'Default Group name' : maestrano.name)
|
8
|
+
group.tenant = 'default' # To be set from SSO parameter
|
9
|
+
group.org_uid = maestrano.org_uid # Maestrano organization UID
|
10
|
+
|
11
|
+
# group.country_alpha2 = maestrano.country
|
12
|
+
# group.free_trial_end_at = maestrano.free_trial_end_at
|
13
|
+
# group.some_required_field = 'some-appropriate-default-value'
|
14
|
+
end
|
15
|
+
|
16
|
+
# Callbacks
|
17
|
+
before_save :update_metadata
|
18
|
+
|
19
|
+
#===================================
|
20
|
+
# Encryptions
|
21
|
+
#===================================
|
22
|
+
attr_encrypted_options[:mode] = :per_attribute_iv_and_salt
|
23
|
+
attr_encrypted :oauth_token, key: ::Settings.encryption_key1
|
24
|
+
attr_encrypted :refresh_token, key: ::Settings.encryption_key2
|
25
|
+
|
26
|
+
#===================================
|
27
|
+
# Associations
|
28
|
+
#===================================
|
29
|
+
has_many :user_organization_rels
|
30
|
+
has_many :users, through: :user_organization_rels
|
31
|
+
has_many :id_maps, dependent: :destroy
|
32
|
+
has_many :synchronizations, dependent: :destroy
|
33
|
+
|
34
|
+
#===================================
|
35
|
+
# Validation
|
36
|
+
#===================================
|
37
|
+
validates :name, presence: true
|
38
|
+
validates :tenant, presence: true
|
39
|
+
validates :uid, uniqueness: {scope: :tenant}
|
40
|
+
validates :oauth_uid, uniqueness: {allow_blank: true, message: 'This account has already been linked'}
|
41
|
+
|
42
|
+
#===================================
|
43
|
+
# Serialized field
|
44
|
+
#===================================
|
45
|
+
serialize :synchronized_entities
|
46
|
+
end
|
47
|
+
|
48
|
+
module ClassMethods
|
49
|
+
end
|
50
|
+
|
51
|
+
def initialize
|
52
|
+
super
|
53
|
+
self.synchronized_entities = {}
|
54
|
+
Maestrano::Connector::Rails::External.entities_list.each do |entity|
|
55
|
+
synchronized_entities[entity.to_sym] = {can_push_to_connec: !pull_disabled, can_push_to_external: !push_disabled}
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def displayable_synchronized_entities
|
60
|
+
result = {}
|
61
|
+
synchronized_entities.each do |entity, hash|
|
62
|
+
begin
|
63
|
+
clazz = "Entities::#{entity.to_s.titleize.split.join}".constantize
|
64
|
+
rescue
|
65
|
+
next
|
66
|
+
end
|
67
|
+
result[entity] = {connec_name: clazz.public_connec_entity_name, external_name: clazz.public_external_entity_name}.merge(hash)
|
68
|
+
end
|
69
|
+
result
|
70
|
+
end
|
71
|
+
|
72
|
+
def add_member(user)
|
73
|
+
user_organization_rels.create(user: user) if tenant == user.tenant && !member?(user)
|
74
|
+
end
|
75
|
+
|
76
|
+
def member?(user)
|
77
|
+
user_organization_rels.where(user_id: user.id).count.positive?
|
78
|
+
end
|
79
|
+
|
80
|
+
def remove_member(user)
|
81
|
+
user_organization_rels.where(user_id: user.id).delete_all
|
82
|
+
end
|
83
|
+
|
84
|
+
def from_omniauth(auth)
|
85
|
+
self.oauth_provider = auth.provider
|
86
|
+
self.oauth_uid = auth.uid
|
87
|
+
self.oauth_token = auth.credentials.token
|
88
|
+
self.refresh_token = auth.credentials.refresh_token
|
89
|
+
self.instance_url = auth.credentials.instance_url
|
90
|
+
save
|
91
|
+
end
|
92
|
+
|
93
|
+
def clear_omniauth
|
94
|
+
self.oauth_uid = nil
|
95
|
+
self.oauth_token = nil
|
96
|
+
self.refresh_token = nil
|
97
|
+
self.sync_enabled = false
|
98
|
+
save
|
99
|
+
end
|
100
|
+
|
101
|
+
# Enable historical data sharing (prior to account linking)
|
102
|
+
def enable_historical_data(enabled)
|
103
|
+
# Historical data sharing cannot be unset
|
104
|
+
return if historical_data
|
105
|
+
if enabled
|
106
|
+
self.date_filtering_limit = nil
|
107
|
+
self.historical_data = true
|
108
|
+
else
|
109
|
+
self.date_filtering_limit ||= Time.now.getlocal
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def last_three_synchronizations_failed?
|
114
|
+
arr = synchronizations.last(3).map(&:error?)
|
115
|
+
arr.count == 3 && arr.uniq == [true]
|
116
|
+
end
|
117
|
+
|
118
|
+
def last_successful_synchronization
|
119
|
+
synchronizations.where(status: 'SUCCESS', partial: false).order(updated_at: :desc).first
|
120
|
+
end
|
121
|
+
|
122
|
+
def last_synchronization_date
|
123
|
+
last_successful_synchronization&.updated_at || date_filtering_limit
|
124
|
+
end
|
125
|
+
|
126
|
+
def reset_synchronized_entities(default = false)
|
127
|
+
synchronized_entities.slice!(*Maestrano::Connector::Rails::External.entities_list.map(&:to_sym))
|
128
|
+
Maestrano::Connector::Rails::External.entities_list.each do |entity|
|
129
|
+
if synchronized_entities[entity.to_sym].is_a?(Hash)
|
130
|
+
can_push_to_external = synchronized_entities[entity.to_sym][:can_push_to_external]
|
131
|
+
can_push_to_connec = synchronized_entities[entity.to_sym][:can_push_to_connec]
|
132
|
+
else
|
133
|
+
can_push_to_external = synchronized_entities[entity.to_sym]
|
134
|
+
can_push_to_connec = synchronized_entities[entity.to_sym]
|
135
|
+
end
|
136
|
+
synchronized_entities[entity.to_sym] = {can_push_to_connec: (can_push_to_connec || default) && !pull_disabled, can_push_to_external: (can_push_to_external || default) && !push_disabled}
|
137
|
+
end
|
138
|
+
save
|
139
|
+
end
|
140
|
+
|
141
|
+
def push_to_connec_enabled?(entity)
|
142
|
+
synchronized_entities.dig(Maestrano::Connector::Rails::EntityHelper.snake_name(entity), :can_push_to_connec) && entity&.class&.can_write_connec?
|
143
|
+
end
|
144
|
+
|
145
|
+
def push_to_external_enabled?(entity)
|
146
|
+
synchronized_entities.dig(Maestrano::Connector::Rails::EntityHelper.snake_name(entity), :can_push_to_external) && entity&.class&.can_write_external?
|
147
|
+
end
|
148
|
+
|
149
|
+
def set_instance_metadata
|
150
|
+
auth = {username: Maestrano[tenant].param('api.id'), password: Maestrano[tenant].param('api.key')}
|
151
|
+
res = HTTParty.get("#{Maestrano[tenant].param('api.host')}/api/v1/account/groups/#{uid}", basic_auth: auth)
|
152
|
+
response = JSON.parse(res.body)
|
153
|
+
self.push_disabled = response.dig('data', 'metadata', 'push_disabled')
|
154
|
+
self.pull_disabled = response.dig('data', 'metadata', 'pull_disabled')
|
155
|
+
end
|
156
|
+
|
157
|
+
def update_metadata
|
158
|
+
set_instance_metadata
|
159
|
+
enable_historical_data(true) if push_disabled
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Maestrano::Connector::Rails::Concerns::Synchronization
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
included do
|
5
|
+
# Keeping only 100 synchronizations per organization
|
6
|
+
after_create :clean_synchronizations
|
7
|
+
|
8
|
+
RUNNING_STATUS = 'RUNNING'.freeze
|
9
|
+
ERROR_STATUS = 'ERROR'.freeze
|
10
|
+
SUCCESS_STATUS = 'SUCCESS'.freeze
|
11
|
+
|
12
|
+
#===================================
|
13
|
+
# Associations
|
14
|
+
#===================================
|
15
|
+
belongs_to :organization
|
16
|
+
|
17
|
+
validates :status, presence: true
|
18
|
+
end
|
19
|
+
|
20
|
+
module ClassMethods
|
21
|
+
def create_running(organization)
|
22
|
+
Maestrano::Connector::Rails::Synchronization.create(organization_id: organization.id, status: RUNNING_STATUS)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def running?
|
27
|
+
status == RUNNING_STATUS
|
28
|
+
end
|
29
|
+
|
30
|
+
def error?
|
31
|
+
status == ERROR_STATUS
|
32
|
+
end
|
33
|
+
|
34
|
+
def success?
|
35
|
+
status == SUCCESS_STATUS
|
36
|
+
end
|
37
|
+
|
38
|
+
def mark_as_success
|
39
|
+
update_attributes(status: SUCCESS_STATUS)
|
40
|
+
end
|
41
|
+
|
42
|
+
def mark_as_error(msg)
|
43
|
+
update_attributes(status: ERROR_STATUS, message: msg)
|
44
|
+
end
|
45
|
+
|
46
|
+
def mark_as_partial
|
47
|
+
update_attributes(partial: true)
|
48
|
+
end
|
49
|
+
|
50
|
+
def clean_synchronizations
|
51
|
+
count = organization.synchronizations.count
|
52
|
+
organization.synchronizations.order('id ASC').limit(count - 100).destroy_all if count > 100
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Maestrano::Connector::Rails::Concerns::User
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
included do
|
5
|
+
# Enable Maestrano for this user
|
6
|
+
maestrano_user_via :provider, :uid, :tenant do |user, maestrano|
|
7
|
+
user.uid = maestrano.uid
|
8
|
+
user.provider = maestrano.provider
|
9
|
+
user.first_name = maestrano.first_name
|
10
|
+
user.last_name = maestrano.last_name
|
11
|
+
user.email = maestrano.email
|
12
|
+
user.tenant = 'default' # To be set from SSO parameter
|
13
|
+
end
|
14
|
+
|
15
|
+
#===================================
|
16
|
+
# Associations
|
17
|
+
#===================================
|
18
|
+
has_many :user_organization_rels, class_name: 'Maestrano::Connector::Rails::UserOrganizationRel'
|
19
|
+
has_many :organizations, through: :user_organization_rels, class_name: 'Maestrano::Connector::Rails::Organization'
|
20
|
+
|
21
|
+
#===================================
|
22
|
+
# Validation
|
23
|
+
#===================================
|
24
|
+
validates :email, presence: true
|
25
|
+
validates :tenant, presence: true
|
26
|
+
end
|
27
|
+
end
|
@@ -1,158 +1,5 @@
|
|
1
1
|
module Maestrano::Connector::Rails
|
2
2
|
class Organization < ActiveRecord::Base
|
3
|
-
|
4
|
-
maestrano_group_via :provider, :uid, :tenant do |group, maestrano|
|
5
|
-
group.name = (maestrano.name.blank? ? 'Default Group name' : maestrano.name)
|
6
|
-
group.tenant = 'default' # To be set from SSO parameter
|
7
|
-
group.org_uid = maestrano.org_uid # Maestrano organization UID
|
8
|
-
|
9
|
-
# group.country_alpha2 = maestrano.country
|
10
|
-
# group.free_trial_end_at = maestrano.free_trial_end_at
|
11
|
-
# group.some_required_field = 'some-appropriate-default-value'
|
12
|
-
end
|
13
|
-
|
14
|
-
def initialize
|
15
|
-
super
|
16
|
-
self.synchronized_entities = {}
|
17
|
-
External.entities_list.each do |entity|
|
18
|
-
self.synchronized_entities[entity.to_sym] = {can_push_to_connec: !self.pull_disabled, can_push_to_external: !self.push_disabled}
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
# Callbacks
|
23
|
-
before_save :update_metadata
|
24
|
-
|
25
|
-
#===================================
|
26
|
-
# Encryptions
|
27
|
-
#===================================
|
28
|
-
attr_encrypted_options[:mode] = :per_attribute_iv_and_salt
|
29
|
-
attr_encrypted :oauth_token, key: ::Settings.encryption_key1
|
30
|
-
attr_encrypted :refresh_token, key: ::Settings.encryption_key2
|
31
|
-
|
32
|
-
#===================================
|
33
|
-
# Associations
|
34
|
-
#===================================
|
35
|
-
has_many :user_organization_rels
|
36
|
-
has_many :users, through: :user_organization_rels
|
37
|
-
has_many :id_maps, dependent: :destroy
|
38
|
-
has_many :synchronizations, dependent: :destroy
|
39
|
-
|
40
|
-
#===================================
|
41
|
-
# Validation
|
42
|
-
#===================================
|
43
|
-
validates :name, presence: true
|
44
|
-
validates :tenant, presence: true
|
45
|
-
validates :uid, uniqueness: {scope: :tenant}
|
46
|
-
validates :oauth_uid, uniqueness: {allow_blank: true, message: 'This account has already been linked'}
|
47
|
-
|
48
|
-
#===================================
|
49
|
-
# Serialized field
|
50
|
-
#===================================
|
51
|
-
serialize :synchronized_entities
|
52
|
-
|
53
|
-
def displayable_synchronized_entities
|
54
|
-
result = {}
|
55
|
-
synchronized_entities.each do |entity, hash|
|
56
|
-
begin
|
57
|
-
clazz = "Entities::#{entity.to_s.titleize.split.join}".constantize
|
58
|
-
rescue
|
59
|
-
next
|
60
|
-
end
|
61
|
-
result[entity] = {connec_name: clazz.public_connec_entity_name, external_name: clazz.public_external_entity_name}.merge(hash)
|
62
|
-
end
|
63
|
-
result
|
64
|
-
end
|
65
|
-
|
66
|
-
def add_member(user)
|
67
|
-
user_organization_rels.create(user: user) if tenant == user.tenant && !member?(user)
|
68
|
-
end
|
69
|
-
|
70
|
-
def member?(user)
|
71
|
-
user_organization_rels.where(user_id: user.id).count.positive?
|
72
|
-
end
|
73
|
-
|
74
|
-
def remove_member(user)
|
75
|
-
user_organization_rels.where(user_id: user.id).delete_all
|
76
|
-
end
|
77
|
-
|
78
|
-
def from_omniauth(auth)
|
79
|
-
self.oauth_provider = auth.provider
|
80
|
-
self.oauth_uid = auth.uid
|
81
|
-
self.oauth_token = auth.credentials.token
|
82
|
-
self.refresh_token = auth.credentials.refresh_token
|
83
|
-
self.instance_url = auth.credentials.instance_url
|
84
|
-
self.save
|
85
|
-
end
|
86
|
-
|
87
|
-
def clear_omniauth
|
88
|
-
self.oauth_uid = nil
|
89
|
-
self.oauth_token = nil
|
90
|
-
self.refresh_token = nil
|
91
|
-
self.sync_enabled = false
|
92
|
-
self.save
|
93
|
-
end
|
94
|
-
|
95
|
-
# Enable historical data sharing (prior to account linking)
|
96
|
-
def enable_historical_data(enabled)
|
97
|
-
# Historical data sharing cannot be unset
|
98
|
-
return if self.historical_data
|
99
|
-
|
100
|
-
if enabled
|
101
|
-
self.date_filtering_limit = nil
|
102
|
-
self.historical_data = true
|
103
|
-
else
|
104
|
-
self.date_filtering_limit ||= Time.now.getlocal
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
def last_three_synchronizations_failed?
|
109
|
-
arr = synchronizations.last(3).map(&:error?)
|
110
|
-
arr.count == 3 && arr.uniq == [true]
|
111
|
-
end
|
112
|
-
|
113
|
-
def last_successful_synchronization
|
114
|
-
synchronizations.where(status: 'SUCCESS', partial: false).order(updated_at: :desc).first
|
115
|
-
end
|
116
|
-
|
117
|
-
def last_synchronization_date
|
118
|
-
last_successful_synchronization&.updated_at || date_filtering_limit
|
119
|
-
end
|
120
|
-
|
121
|
-
def reset_synchronized_entities(default = false)
|
122
|
-
synchronized_entities.slice!(*External.entities_list.map(&:to_sym))
|
123
|
-
External.entities_list.each do |entity|
|
124
|
-
if synchronized_entities[entity.to_sym].is_a?(Hash)
|
125
|
-
can_push_to_external = synchronized_entities[entity.to_sym][:can_push_to_external]
|
126
|
-
can_push_to_connec = synchronized_entities[entity.to_sym][:can_push_to_connec]
|
127
|
-
else
|
128
|
-
can_push_to_external = synchronized_entities[entity.to_sym]
|
129
|
-
can_push_to_connec = synchronized_entities[entity.to_sym]
|
130
|
-
end
|
131
|
-
synchronized_entities[entity.to_sym] = {can_push_to_connec: (can_push_to_connec || default) && !pull_disabled, can_push_to_external: (can_push_to_external || default) && !push_disabled}
|
132
|
-
end
|
133
|
-
save
|
134
|
-
end
|
135
|
-
|
136
|
-
def push_to_connec_enabled?(entity)
|
137
|
-
synchronized_entities.dig(EntityHelper.snake_name(entity), :can_push_to_connec) && entity&.class&.can_write_connec?
|
138
|
-
end
|
139
|
-
|
140
|
-
def push_to_external_enabled?(entity)
|
141
|
-
synchronized_entities.dig(EntityHelper.snake_name(entity), :can_push_to_external) && entity&.class&.can_write_external?
|
142
|
-
end
|
143
|
-
|
144
|
-
def set_instance_metadata
|
145
|
-
auth = {username: Maestrano[tenant].param('api.id'), password: Maestrano[tenant].param('api.key')}
|
146
|
-
res = HTTParty.get("#{Maestrano[tenant].param('api.host')}/api/v1/account/groups/#{uid}", basic_auth: auth)
|
147
|
-
response = JSON.parse(res.body)
|
148
|
-
|
149
|
-
self.push_disabled = response.dig('data', 'metadata', 'push_disabled')
|
150
|
-
self.pull_disabled = response.dig('data', 'metadata', 'pull_disabled')
|
151
|
-
end
|
152
|
-
|
153
|
-
def update_metadata
|
154
|
-
self.set_instance_metadata
|
155
|
-
self.enable_historical_data(true) if self.push_disabled
|
156
|
-
end
|
3
|
+
include Maestrano::Connector::Rails::Concerns::Organization
|
157
4
|
end
|
158
5
|
end
|
@@ -1,50 +1,5 @@
|
|
1
1
|
module Maestrano::Connector::Rails
|
2
2
|
class Synchronization < ActiveRecord::Base
|
3
|
-
|
4
|
-
after_create :clean_synchronizations
|
5
|
-
|
6
|
-
RUNNING_STATUS = 'RUNNING'.freeze
|
7
|
-
ERROR_STATUS = 'ERROR'.freeze
|
8
|
-
SUCCESS_STATUS = 'SUCCESS'.freeze
|
9
|
-
|
10
|
-
#===================================
|
11
|
-
# Associations
|
12
|
-
#===================================
|
13
|
-
belongs_to :organization
|
14
|
-
|
15
|
-
validates :status, presence: true
|
16
|
-
|
17
|
-
def running?
|
18
|
-
status == RUNNING_STATUS
|
19
|
-
end
|
20
|
-
|
21
|
-
def error?
|
22
|
-
status == ERROR_STATUS
|
23
|
-
end
|
24
|
-
|
25
|
-
def success?
|
26
|
-
status == SUCCESS_STATUS
|
27
|
-
end
|
28
|
-
|
29
|
-
def self.create_running(organization)
|
30
|
-
Synchronization.create(organization_id: organization.id, status: RUNNING_STATUS)
|
31
|
-
end
|
32
|
-
|
33
|
-
def set_success
|
34
|
-
update_attributes(status: SUCCESS_STATUS)
|
35
|
-
end
|
36
|
-
|
37
|
-
def set_error(msg)
|
38
|
-
update_attributes(status: ERROR_STATUS, message: msg)
|
39
|
-
end
|
40
|
-
|
41
|
-
def set_partial
|
42
|
-
update_attributes(partial: true)
|
43
|
-
end
|
44
|
-
|
45
|
-
def clean_synchronizations
|
46
|
-
count = organization.synchronizations.count
|
47
|
-
organization.synchronizations.order('id ASC').limit(count - 100).destroy_all if count > 100
|
48
|
-
end
|
3
|
+
include Maestrano::Connector::Rails::Concerns::Synchronization
|
49
4
|
end
|
50
5
|
end
|
@@ -1,25 +1,5 @@
|
|
1
1
|
module Maestrano::Connector::Rails
|
2
2
|
class User < ActiveRecord::Base
|
3
|
-
|
4
|
-
maestrano_user_via :provider, :uid, :tenant do |user, maestrano|
|
5
|
-
user.uid = maestrano.uid
|
6
|
-
user.provider = maestrano.provider
|
7
|
-
user.first_name = maestrano.first_name
|
8
|
-
user.last_name = maestrano.last_name
|
9
|
-
user.email = maestrano.email
|
10
|
-
user.tenant = 'default' # To be set from SSO parameter
|
11
|
-
end
|
12
|
-
|
13
|
-
#===================================
|
14
|
-
# Associations
|
15
|
-
#===================================
|
16
|
-
has_many :user_organization_rels
|
17
|
-
has_many :organizations, through: :user_organization_rels
|
18
|
-
|
19
|
-
#===================================
|
20
|
-
# Validation
|
21
|
-
#===================================
|
22
|
-
validates :email, presence: true
|
23
|
-
validates :tenant, presence: true
|
3
|
+
include Maestrano::Connector::Rails::Concerns::User
|
24
4
|
end
|
25
5
|
end
|
data/config/routes.rb
CHANGED
@@ -4,13 +4,13 @@ Maestrano::Connector::Rails::Engine.routes.draw do
|
|
4
4
|
get 'version', to: 'version#index'
|
5
5
|
|
6
6
|
namespace :maestrano do
|
7
|
-
match 'signout', to: 'sessions#destroy', as: 'signout', via: [
|
7
|
+
match 'signout', to: 'sessions#destroy', as: 'signout', via: %i[get post]
|
8
8
|
post 'connec/notifications/:tenant' => 'connec#notifications'
|
9
9
|
|
10
10
|
resources :dependancies, only: [:index]
|
11
11
|
|
12
12
|
scope ':tenant' do
|
13
|
-
resources :synchronizations, only: [
|
13
|
+
resources :synchronizations, only: %i[show create] do
|
14
14
|
collection do
|
15
15
|
put :toggle_sync
|
16
16
|
put :update_metadata
|
@@ -33,6 +33,11 @@ module Connector
|
|
33
33
|
copy_file 'example_entity_spec.rb', 'spec/models/entities/example_entitiy.rb'
|
34
34
|
end
|
35
35
|
|
36
|
+
def copy_icons_and_logos
|
37
|
+
copy_file 'logos/to_connec.png', 'app/assets/images/logos/to_connec.png'
|
38
|
+
copy_file 'logos/to_external.png', 'spec/assets/images/logos/to_external.png'
|
39
|
+
end
|
40
|
+
|
36
41
|
def copy_controllers_and_views
|
37
42
|
copy_file 'home_controller.rb', 'app/controllers/home_controller.rb'
|
38
43
|
copy_file 'home_controller_spec.rb', 'spec/controllers/home_controller_spec.rb'
|
@@ -10,7 +10,7 @@ class HomeController < ApplicationController
|
|
10
10
|
end
|
11
11
|
full_sync = params['historical-data'].present? && !current_organization.historical_data
|
12
12
|
opts = {full_sync: full_sync}
|
13
|
-
current_organization.sync_enabled = current_organization.synchronized_entities.values.any?
|
13
|
+
current_organization.sync_enabled = current_organization.synchronized_entities.values.any? { |settings| settings.values.any? { |v| v } }
|
14
14
|
current_organization.enable_historical_data(params['historical-data'].present?)
|
15
15
|
trigger_sync = current_organization.sync_enabled
|
16
16
|
current_organization.save
|
@@ -3,7 +3,7 @@ require 'spec_helper'
|
|
3
3
|
describe HomeController, type: :controller do
|
4
4
|
let(:back_path) { home_index_path }
|
5
5
|
|
6
|
-
before(:each) { request.env['HTTP_REFERER'] = back_path
|
6
|
+
before(:each) { request.env['HTTP_REFERER'] = back_path}
|
7
7
|
|
8
8
|
describe 'index' do
|
9
9
|
subject { get :index }
|
@@ -13,12 +13,14 @@ describe HomeController, type: :controller do
|
|
13
13
|
|
14
14
|
describe 'update' do
|
15
15
|
let(:user) { create(:user) }
|
16
|
-
let(:organization) { create(:organization, synchronized_entities: {'people' => false, 'item' => true}) }
|
16
|
+
let(:organization) { create(:organization, synchronized_entities: {'people' => {can_push_to_connec: false, can_push_to_external: false}, 'item' => {can_push_to_connec: true, can_push_to_external: true}}) }
|
17
17
|
|
18
|
-
before
|
19
|
-
|
18
|
+
before do
|
19
|
+
allow_any_instance_of(Maestrano::Connector::Rails::SessionHelper).to receive(:current_user).and_return(user)
|
20
|
+
allow_any_instance_of(Maestrano::Connector::Rails::SessionHelper).to receive(:current_organization).and_return(organization)
|
21
|
+
end
|
20
22
|
|
21
|
-
subject { put :update, id: organization.id, 'people' =>
|
23
|
+
subject { put :update, id: organization.id, 'people' => {to_connec: '1', to_external: '1'}, 'item' => {}, 'lala' => {} }
|
22
24
|
|
23
25
|
context 'when user is not admin' do
|
24
26
|
before { allow_any_instance_of(Maestrano::Connector::Rails::SessionHelper).to receive(:is_admin).and_return(false) }
|
@@ -34,7 +36,7 @@ describe HomeController, type: :controller do
|
|
34
36
|
it 'updates organization synchronized_entities' do
|
35
37
|
subject
|
36
38
|
organization.reload
|
37
|
-
expect(organization.synchronized_entities).to eq('people' => true, 'item' => false)
|
39
|
+
expect(organization.synchronized_entities).to eq('people' => {can_push_to_connec: true, can_push_to_external: true}, 'item' => {can_push_to_connec: false, can_push_to_external: false})
|
38
40
|
end
|
39
41
|
|
40
42
|
it 'updates organization sync_enabled' do
|
@@ -44,7 +46,7 @@ describe HomeController, type: :controller do
|
|
44
46
|
end
|
45
47
|
|
46
48
|
context 'when removing all entities' do
|
47
|
-
subject { put :update, id: organization.id, 'people' =>
|
49
|
+
subject { put :update, id: organization.id, 'people' => {}, 'item' => {} }
|
48
50
|
before { organization.update(sync_enabled: true) }
|
49
51
|
|
50
52
|
it 'set sync_enabled to false' do
|
@@ -58,10 +60,12 @@ describe HomeController, type: :controller do
|
|
58
60
|
|
59
61
|
describe 'synchronize' do
|
60
62
|
let(:user) { create(:user) }
|
61
|
-
let(:organization) { create(:organization, synchronized_entities: {'people' => false, 'item' => true}) }
|
63
|
+
let(:organization) { create(:organization, synchronized_entities: {'people' => {can_push_to_connec: false, can_push_to_external: false}, 'item' => {can_push_to_connec: true, can_push_to_external: true}}) }
|
62
64
|
|
63
|
-
before
|
64
|
-
|
65
|
+
before do
|
66
|
+
allow_any_instance_of(Maestrano::Connector::Rails::SessionHelper).to receive(:current_user).and_return(user)
|
67
|
+
allow_any_instance_of(Maestrano::Connector::Rails::SessionHelper).to receive(:current_organization).and_return(organization)
|
68
|
+
end
|
65
69
|
|
66
70
|
subject { post :synchronize }
|
67
71
|
|
@@ -102,10 +106,14 @@ describe HomeController, type: :controller do
|
|
102
106
|
end
|
103
107
|
|
104
108
|
describe 'redirect_to_external' do
|
109
|
+
let(:user) { create(:user) }
|
110
|
+
let(:organization) { create(:organization) }
|
105
111
|
subject { get :redirect_to_external }
|
106
112
|
|
107
|
-
|
108
|
-
|
113
|
+
before do
|
114
|
+
allow_any_instance_of(Maestrano::Connector::Rails::SessionHelper).to receive(:current_organization).and_return(organization)
|
109
115
|
end
|
116
|
+
|
117
|
+
it {expect(subject).to redirect_to('https://somewhere.com')}
|
110
118
|
end
|
111
119
|
end
|
@@ -9,7 +9,7 @@
|
|
9
9
|
-if current_organization
|
10
10
|
Link your company <strong>#{current_organization.name} (#{current_organization.uid})</strong> to ApplicationName to get your business in synch. Check the status of your connection on this screen.
|
11
11
|
-else
|
12
|
-
|
12
|
+
ApplicationName add-on is a microservice providing data synchronization between your platform and ApplicationName
|
13
13
|
|
14
14
|
.container
|
15
15
|
- if current_user
|
@@ -127,9 +127,3 @@
|
|
127
127
|
.row
|
128
128
|
.col-md-4.col-md-offset-4.text-center
|
129
129
|
= link_to 'Go to ApplicationName', home_redirect_to_external_path, class: 'btn btn-lg btn-primary'
|
130
|
-
|
131
|
-
- else
|
132
|
-
.row
|
133
|
-
.col-md-4.col-md-offset-4.center
|
134
|
-
= link_to 'Link your Maestrano account', Maestrano::Connector::Rails::Engine.routes.url_helpers.default_maestrano_auth_saml_index_path(tenant: :default), class: 'btn btn-warning'
|
135
|
-
|
@@ -4,8 +4,8 @@
|
|
4
4
|
%html
|
5
5
|
%head
|
6
6
|
%title ApplicationName Connector
|
7
|
-
= stylesheet_link_tag 'application', media: 'all'
|
8
|
-
= javascript_include_tag 'application'
|
7
|
+
= stylesheet_link_tag 'application', media: 'all'
|
8
|
+
= javascript_include_tag 'application'
|
9
9
|
%script{src: 'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js', integrity: 'sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa', crossorigin: 'anonymous'}
|
10
10
|
= csrf_meta_tags
|
11
11
|
%body
|
Binary file
|
Binary file
|
@@ -31,6 +31,7 @@ Gem::Specification.new do |s|
|
|
31
31
|
s.add_runtime_dependency('bootstrap-sass')
|
32
32
|
s.add_runtime_dependency('config')
|
33
33
|
s.add_runtime_dependency('figaro')
|
34
|
+
s.add_runtime_dependency('jquery-rails')
|
34
35
|
s.add_runtime_dependency('haml-rails')
|
35
36
|
s.add_runtime_dependency('hash_mapper', '>= 0.2.2')
|
36
37
|
|
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.0.2.pre.
|
4
|
+
version: 2.0.2.pre.RC10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Maestrano
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-04-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -108,6 +108,20 @@ dependencies:
|
|
108
108
|
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: jquery-rails
|
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'
|
111
125
|
- !ruby/object:Gem::Dependency
|
112
126
|
name: haml-rails
|
113
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -393,6 +407,7 @@ files:
|
|
393
407
|
- app/helpers/maestrano/connector/rails/entity_helper.rb
|
394
408
|
- app/helpers/maestrano/connector/rails/session_helper.rb
|
395
409
|
- app/jobs/maestrano/connector/rails/all_synchronizations_job.rb
|
410
|
+
- app/jobs/maestrano/connector/rails/concerns/synchronization_job.rb
|
396
411
|
- app/jobs/maestrano/connector/rails/push_to_connec_job.rb
|
397
412
|
- app/jobs/maestrano/connector/rails/push_to_connec_worker.rb
|
398
413
|
- app/jobs/maestrano/connector/rails/synchronization_job.rb
|
@@ -403,7 +418,11 @@ files:
|
|
403
418
|
- app/models/maestrano/connector/rails/concerns/entity.rb
|
404
419
|
- app/models/maestrano/connector/rails/concerns/entity_base.rb
|
405
420
|
- app/models/maestrano/connector/rails/concerns/external.rb
|
421
|
+
- app/models/maestrano/connector/rails/concerns/id_map.rb
|
422
|
+
- app/models/maestrano/connector/rails/concerns/organization.rb
|
406
423
|
- app/models/maestrano/connector/rails/concerns/sub_entity_base.rb
|
424
|
+
- app/models/maestrano/connector/rails/concerns/synchronization.rb
|
425
|
+
- app/models/maestrano/connector/rails/concerns/user.rb
|
407
426
|
- app/models/maestrano/connector/rails/connec_helper.rb
|
408
427
|
- app/models/maestrano/connector/rails/connector_logger.rb
|
409
428
|
- app/models/maestrano/connector/rails/entity.rb
|
@@ -451,6 +470,8 @@ files:
|
|
451
470
|
- lib/generators/connector/templates/home_controller_spec.rb
|
452
471
|
- lib/generators/connector/templates/home_index.haml
|
453
472
|
- lib/generators/connector/templates/layouts.haml
|
473
|
+
- lib/generators/connector/templates/logos/to_connec.png
|
474
|
+
- lib/generators/connector/templates/logos/to_external.png
|
454
475
|
- lib/generators/connector/templates/oauth_controller.rb
|
455
476
|
- lib/generators/connector/templates/shared_entities_controller.rb
|
456
477
|
- lib/generators/connector/templates/shared_entities_controller_spec.rb
|
@@ -490,7 +511,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
490
511
|
version: 1.3.1
|
491
512
|
requirements: []
|
492
513
|
rubyforge_project:
|
493
|
-
rubygems_version: 2.
|
514
|
+
rubygems_version: 2.5.1
|
494
515
|
signing_key:
|
495
516
|
specification_version: 4
|
496
517
|
summary: Rails framework to build connector with Maestrano
|