maestrano-connector-rails 0.2.11 → 0.2.12
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +0 -3
- data/README.md +38 -20
- data/VERSION +1 -1
- data/app/controllers/maestrano/connec_controller.rb +6 -10
- data/app/jobs/maestrano/connector/rails/push_to_connec_job.rb +43 -0
- data/app/models/maestrano/connector/rails/complex_entity.rb +2 -2
- data/app/models/maestrano/connector/rails/concerns/entity.rb +13 -3
- data/lib/generators/connector/install_generator.rb +1 -2
- data/lib/generators/connector/templates/complex_entity_example/contact.rb +8 -0
- data/lib/generators/connector/templates/complex_entity_example/lead.rb +8 -0
- data/lib/generators/connector/templates/complex_entity_example/person.rb +8 -0
- data/lib/generators/connector/templates/example_entity.rb +9 -0
- data/maestrano-connector-rails.gemspec +5 -3
- data/spec/controllers/connec_controller_spec.rb +3 -0
- data/spec/jobs/push_to_connec_job_spec.rb +97 -0
- data/spec/models/complex_entity_spec.rb +8 -0
- data/spec/models/entity_spec.rb +26 -0
- data/template/maestrano-connector-template.rb +12 -2
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0ede31586bf582ced3d9a9024968edc3ac1d1732
|
4
|
+
data.tar.gz: da7c491c555373c153650012442613b9edb8f6fb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 00e346e7cc00061e7c3c5377f51afb23f78fc59904cdad730016e9b3b11d8c72eb9d40e0e7929fc4a5d81103d09a98b253894a1e714ed8467213b5ca1798aa63
|
7
|
+
data.tar.gz: 9078bb564275af62c3646b496e771c78777824f8d60b23c35b9ffc990a18ff9be881e7057fea0a1220890623352432ee61aea1cf4bfba70dfa166e14231cce7c
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
[ ![Codeship Status for maestrano/maestrano-connector-rails](https://codeship.com/projects/e7990b70-b04d-0133-c4e7-5e399acd7f73/status?branch=master)](https://codeship.com/projects/132645)
|
2
|
+
[![Code Climate](https://codeclimate.com/github/maestrano/maestrano-connector-rails/badges/gpa.svg)](https://codeclimate.com/github/maestrano/maestrano-connector-rails)
|
2
3
|
|
3
4
|
<p align="center">
|
4
5
|
<img src="https://raw.github.com/maestrano/maestrano-connector-rails/master/maestrano.png" alt="Maestrano Logo">
|
@@ -6,7 +7,7 @@
|
|
6
7
|
<br/>
|
7
8
|
</p>
|
8
9
|
|
9
|
-
Maestrano Connector Engine
|
10
|
+
Maestrano Connector is a Rails Engine that bootstraps the implementation of data syncrhonization between an external application API and the Maestrano ecosystem.
|
10
11
|
|
11
12
|
Maestrano Connector Integration is currently in closed beta. Want to know more? Send us an email to <contact@maestrano.com>.
|
12
13
|
|
@@ -22,23 +23,23 @@ Maestrano Connector Integration is currently in closed beta. Want to know more?
|
|
22
23
|
* [Mapping entities](#mapping-entities)
|
23
24
|
4. [Pages controllers and views](#pages-controllers-and-views)
|
24
25
|
5. [Complex entities](#complex-entities)
|
26
|
+
6. [Webhooks](#Webhooks)
|
25
27
|
|
26
28
|
- - -
|
27
29
|
|
28
30
|
## Getting Setup
|
29
|
-
Before integrating with us you will need
|
31
|
+
Before integrating with us you will need to have your application registered on the Maestrano platform. Please refer to the online documentation we provide: https://maestrano.atlassian.net/wiki/display/CONNECAPIV2/Maestrano+Developers
|
30
32
|
|
31
33
|
## Getting Started
|
32
|
-
Create a new rails application using the connector template
|
34
|
+
Create a new rails application using the connector template. The template works with both Ruby 2.2 and jRuby 9.0.4.0, you will be asked which one you want to use.
|
33
35
|
```console
|
34
|
-
rails new <project_name> -m https://raw.githubusercontent.com/
|
36
|
+
rails new <project_name> -m https://raw.githubusercontent.com/Maestrano/maestrano-connector-rails/master/template/maestrano-connector-template.rb
|
35
37
|
```
|
36
38
|
|
37
39
|
If and only if you have an error in the template's rails generate step, you'll need to re-run the following command in your project folder:
|
38
40
|
```console
|
39
41
|
bundle
|
40
42
|
rails g connector:install
|
41
|
-
rails g delayed_job:active_record
|
42
43
|
rake db:migrate
|
43
44
|
```
|
44
45
|
|
@@ -50,17 +51,18 @@ connec_api_id: 'API_ID'
|
|
50
51
|
connec_api_key: 'API_KEY'
|
51
52
|
```
|
52
53
|
|
53
|
-
The
|
54
|
+
The next thing you need to do is to set your configuration in config/initializers/maestrano.rb. You will need to define where your application will be publicly hosted:
|
54
55
|
```ruby
|
55
56
|
config.app.host = 'http://path_to_app'
|
56
57
|
```
|
57
58
|
The rest of the config has default values, so you can take a look but you don't really need to change anything else.
|
59
|
+
For a more detailed configuration, please refer to https://github.com/maestrano/maestrano-ruby#configuration
|
58
60
|
|
59
|
-
Please note that the connectors support multi-tenancy, so you may have to set up configuration for
|
61
|
+
Please note that the connectors support multi-tenancy, so you may have to set up configuration for tenants other than the Maestrano platform (the default one).
|
60
62
|
|
61
|
-
|
63
|
+
These configuration are automatically retrieved by Maestrano via a metadata endpoint that is provided by the gem, so you're all setup as it is.
|
62
64
|
|
63
|
-
Time to test! If your launch your application (please make sure that you launch the application on the same path as the one in the config file). If you click on the 'Link your Maestrano account' link on your connector home page, you should be able to do a full
|
65
|
+
Time to test! If your launch your application (please make sure that you launch the application on the same path as the one in the config file). If you click on the 'Link your Maestrano account' link on your connector home page, you should be able to do a full SSO process with Maestrano.
|
64
66
|
|
65
67
|
### Integration with the external application
|
66
68
|
|
@@ -74,13 +76,13 @@ If all went well, you should now be able to use the 'Link this company to...' li
|
|
74
76
|
|
75
77
|
## Preparing synchronizations
|
76
78
|
|
77
|
-
The aim of the connector is to perform synchronizations between Connec!™ and the external application, meaning fetching data on both ends, process them, and push the result to the relevant
|
79
|
+
The aim of the connector is to perform synchronizations between Connec!™ and the external application, meaning fetching data on both ends, process them, and push the result to the relevant parties. The Connec!™ part and the synchronization process itself is handled by the engine, so all you have to do is to implements some methods to bridge the calls to the external application.
|
78
80
|
|
79
|
-
###
|
81
|
+
### external.rb
|
80
82
|
|
81
|
-
First file to look for is
|
83
|
+
First file to look for is `models/maestrano/connector/rails/external.rb`. It contains two methods that you need to implement:
|
82
84
|
|
83
|
-
* external_name, which is used
|
85
|
+
* external_name, which is used for logging purpose only, and should only return the name of the external application, e.g.
|
84
86
|
```ruby
|
85
87
|
def self.external_name
|
86
88
|
'This awesome CRM'
|
@@ -89,23 +91,23 @@ end
|
|
89
91
|
* get_client, which should return either the external application gem api client, or, in the worst case, a custom HTTParty client.
|
90
92
|
|
91
93
|
|
92
|
-
###
|
94
|
+
### entity.rb
|
93
95
|
|
94
|
-
The second important file is
|
96
|
+
The second important file is `models/maestrano/connector/rails/entity.rb`. It contains a method to declare the entities synchronizable by your connector (more on that later), some methods to retrieve and send data to the external application API, and lastly two methods to extract `id` and `timestamps` from the entity format sent by the external application.
|
95
97
|
|
96
98
|
The details of each methods are explained in the entity.rb file provided.
|
97
99
|
|
98
100
|
### Mapping entities
|
99
101
|
|
100
|
-
Now that you're all setup with both Connec!™ and the external application, it's time to decide which entities (contacts, accounts, events, ...) you want to synchronize. For each type of entity your connector will synchronize, you will need to create a class that inherits from Maestrano::Connector::Rails::Entity
|
102
|
+
Now that you're all setup with both Connec!™ and the external application, it's time to decide which entities (contacts, accounts, events, ...) you want to synchronize. For each type of entity your connector will synchronize, you will need to create a class that inherits from `Maestrano::Connector::Rails::Entity`.
|
101
103
|
|
102
104
|
An example of such a class in provided in the models/entities/ folder, and demonstrates which methods you'll need to implements for each entity. The main thing to do is the mapping between the external entity and the Connec!™ entity. For the mapping, we use the hash_mapper gem (<https://github.com/ismasan/hash_mapper>).
|
103
105
|
|
104
|
-
This type of entity class enable
|
106
|
+
This type of entity class enable one-to-one model correspondance. For more complex needs, please refer to the complex entity section below.
|
105
107
|
|
106
108
|
You'll find the connec API documentation here: <http://maestrano.github.io/connec/>, and should also refer to the external application API documentation.
|
107
109
|
|
108
|
-
Also don
|
110
|
+
Also don't forget that each entity your connector synchronize should be declared in the entity.rb class, and, because the synchronizable entities are stored in the local database for each organization, you'll need to create a migration for exisiting organization if you add an new entity.
|
109
111
|
|
110
112
|
#### Overriding methods
|
111
113
|
|
@@ -141,11 +143,27 @@ The home and admin pages views and controllers are provided as example, but you
|
|
141
143
|
|
142
144
|
## Complex entities
|
143
145
|
|
144
|
-
For more complex correspondances, like
|
146
|
+
For more complex correspondances, like one-to-many or many-to-many ones, you can use the complex entity workflow. To see how it works, you can run
|
145
147
|
```console
|
146
148
|
rails g connector:complex_entity
|
147
149
|
```
|
148
150
|
|
149
|
-
This will generate some example files demonstrating a
|
151
|
+
This will generate some example files demonstrating a one-to-many correspondance between Connec!™ person and external contact and lead data models.
|
150
152
|
|
151
153
|
The complex entities workflow uses two methods to pre-process data which you have to implements for each complex entity (see contact_and_lead.rb). They are called before the mapping step, and you can use them to perform any data model specific operations.
|
154
|
+
|
155
|
+
## Webhooks
|
156
|
+
|
157
|
+
Connec!™ issues webhooks each time an entity is created or updated. This allows real time integration from Connec!™ to the application you're integrating with. All you have to do is subscribe to the webhooks on the entities your interested in (in your Maestrano.rb file), everything else is magically handled by the gem.
|
158
|
+
|
159
|
+
If the application you're integrating with support webhooks, you can and should use them to allow a full real time integration. The gem provide a job to help you do that. It will perform the necessary checks, mappings and then push the entities to Connec!™. All you have to do is build a controller and config the necessary routes to catch the webhook, and call this job. For example:
|
160
|
+
```ruby
|
161
|
+
class ExternalWebhooksController < ApplicationController
|
162
|
+
def notification
|
163
|
+
organization = # find organization from webhook params
|
164
|
+
Maestrano::Connector::Rails::PushToConnecJob.perform_later(organization, params[:notif][:name], parmas[:notif][:objects])
|
165
|
+
end
|
166
|
+
end
|
167
|
+
```
|
168
|
+
|
169
|
+
If you have questions, please contact the technical team <developers@maestrano.com>.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.12
|
@@ -45,16 +45,12 @@ class Maestrano::ConnecController < Maestrano::Rails::WebHookController
|
|
45
45
|
|
46
46
|
private
|
47
47
|
def find_entity_instance(entity_name)
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
if instance.
|
54
|
-
return {instance: instance, is_complex: true, name: entity_name_from_list} if instance.connec_entities_names.include?(entity_name.singularize)
|
55
|
-
elsif instance.methods.include?('connec_entity_name'.to_sym)
|
56
|
-
return {instance: instance, is_complex: false, name: entity_name_from_list} if instance.connec_entity_name == entity_name.singularize
|
57
|
-
end
|
48
|
+
Maestrano::Connector::Rails::Entity.entities_list.each do |entity_name_from_list|
|
49
|
+
instance = "Entities::#{entity_name_from_list.singularize.titleize.split.join}".constantize.new
|
50
|
+
if instance.methods.include?('connec_entities_names'.to_sym)
|
51
|
+
return {instance: instance, is_complex: true, name: entity_name_from_list} if instance.connec_entities_names.include?(entity_name.singularize)
|
52
|
+
elsif instance.methods.include?('connec_entity_name'.to_sym)
|
53
|
+
return {instance: instance, is_complex: false, name: entity_name_from_list} if instance.connec_entity_name == entity_name.singularize
|
58
54
|
end
|
59
55
|
end
|
60
56
|
nil
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Maestrano::Connector::Rails
|
2
|
+
class PushToConnecJob < ::ActiveJob::Base
|
3
|
+
queue_as :default
|
4
|
+
|
5
|
+
# expected hash: {"external_entity_name1" => [entity1, entity2], "external_entity_name2" => []}
|
6
|
+
def perform(organization, entities_hash)
|
7
|
+
return unless organization.sync_enabled && organization.oauth_uid
|
8
|
+
|
9
|
+
connec_client = Maestrano::Connec::Client.new(organization.uid)
|
10
|
+
|
11
|
+
entities_hash.each do |external_entity_name, entities|
|
12
|
+
if entity_instance_hash = find_entity_instance(external_entity_name)
|
13
|
+
entity_instance = entity_instance_hash[:instance]
|
14
|
+
next unless organization.synchronized_entities[entity_instance_hash[:name].to_sym]
|
15
|
+
|
16
|
+
if entity_instance_hash[:is_complex]
|
17
|
+
entities = Hash[ *entity_instance.external_entities_names.collect{|name| name == external_entity_name.singularize ? [name, entities] : [ name, []]}.flatten(1) ]
|
18
|
+
entity_instance.consolidate_and_map_data(Hash[ *entity_instance.connec_entities_names.collect{|name| [ name, []]}.flatten(1) ], entities, organization, {})
|
19
|
+
else
|
20
|
+
entity_instance.consolidate_and_map_data([], entities, organization, {})
|
21
|
+
end
|
22
|
+
|
23
|
+
entity_instance.push_entities_to_connec(connec_client, entities, organization)
|
24
|
+
else
|
25
|
+
Rails.logger.warn "Called push to connec job with unknow entity: #{external_entity_name}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
def find_entity_instance(entity_name)
|
32
|
+
Maestrano::Connector::Rails::Entity.entities_list.each do |entity_name_from_list|
|
33
|
+
instance = "Entities::#{entity_name_from_list.singularize.titleize.split.join}".constantize.new
|
34
|
+
if instance.methods.include?('external_entities_names'.to_sym)
|
35
|
+
return {instance: instance, is_complex: true, name: entity_name_from_list} if instance.external_entities_names.include?(entity_name.singularize)
|
36
|
+
elsif instance.methods.include?('external_entity_name'.to_sym)
|
37
|
+
return {instance: instance, is_complex: false, name: entity_name_from_list} if instance.external_entity_name == entity_name.singularize
|
38
|
+
end
|
39
|
+
end
|
40
|
+
nil
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -59,7 +59,7 @@ module Maestrano::Connector::Rails
|
|
59
59
|
ConnectorLogger.log('info', organization, "Discard Connec! #{connec_entity_name} : #{entity}")
|
60
60
|
nil
|
61
61
|
else
|
62
|
-
{entity: sub_entity_instance.map_to(external_entity_name, entity, organization), idmap: idmap || IdMap.create(connec_id: entity['id'], connec_entity: connec_entity_name.downcase, external_entity: external_entity_name.downcase, organization_id: organization.id)}
|
62
|
+
{entity: sub_entity_instance.map_to(external_entity_name, entity, organization), idmap: idmap || IdMap.create(connec_id: entity['id'], connec_entity: connec_entity_name.downcase, external_entity: external_entity_name.downcase, organization_id: organization.id, name: sub_entity_instance.object_name_from_connec_entity_hash(entity))}
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
@@ -99,7 +99,7 @@ module Maestrano::Connector::Rails
|
|
99
99
|
|
100
100
|
# No idmap: creating one, nothing else to do
|
101
101
|
unless idmap
|
102
|
-
next {entity: sub_entity_instance.map_to(connec_entity_name, entity, organization), idmap: IdMap.create(external_id: sub_entity_instance.get_id_from_external_entity_hash(entity), external_entity: external_entity_name.downcase, connec_entity: connec_entity_name.downcase, organization_id: organization.id)}
|
102
|
+
next {entity: sub_entity_instance.map_to(connec_entity_name, entity, organization), idmap: IdMap.create(external_id: sub_entity_instance.get_id_from_external_entity_hash(entity), external_entity: external_entity_name.downcase, connec_entity: connec_entity_name.downcase, organization_id: organization.id, name: sub_entity_instance.object_name_from_external_entity_hash(entity))}
|
103
103
|
end
|
104
104
|
|
105
105
|
# Entity has not been modified since its last push to connec!
|
@@ -118,7 +118,7 @@ module Maestrano::Connector::Rails::Concerns::Entity
|
|
118
118
|
Maestrano::Connector::Rails::ConnectorLogger.log('info', organization, "Discard Connec! #{self.connec_entity_name} : #{entity}")
|
119
119
|
nil
|
120
120
|
else
|
121
|
-
{entity: self.map_to_external(entity, organization), idmap: idmap || Maestrano::Connector::Rails::IdMap.create(connec_id: entity['id'], connec_entity: self.connec_entity_name.downcase, organization_id: organization.id)}
|
121
|
+
{entity: self.map_to_external(entity, organization), idmap: idmap || Maestrano::Connector::Rails::IdMap.create(connec_id: entity['id'], connec_entity: self.connec_entity_name.downcase, organization_id: organization.id, name: object_name_from_connec_entity_hash(entity))}
|
122
122
|
end
|
123
123
|
end
|
124
124
|
|
@@ -189,7 +189,7 @@ module Maestrano::Connector::Rails::Concerns::Entity
|
|
189
189
|
|
190
190
|
# No idmap: creating one, nothing else to do
|
191
191
|
unless idmap
|
192
|
-
next {entity: self.map_to_connec(entity, organization), idmap: Maestrano::Connector::Rails::IdMap.create(external_id: self.get_id_from_external_entity_hash(entity), external_entity: self.external_entity_name.downcase, organization_id: organization.id)}
|
192
|
+
next {entity: self.map_to_connec(entity, organization), idmap: Maestrano::Connector::Rails::IdMap.create(external_id: self.get_id_from_external_entity_hash(entity), external_entity: self.external_entity_name.downcase, organization_id: organization.id, name: self.object_name_from_external_entity_hash(entity))}
|
193
193
|
end
|
194
194
|
|
195
195
|
# Not pushing entity to Connec!
|
@@ -234,7 +234,7 @@ module Maestrano::Connector::Rails::Concerns::Entity
|
|
234
234
|
# Entity specific methods
|
235
235
|
# Those methods need to be define in each entity
|
236
236
|
# ----------------------------------------------
|
237
|
-
|
237
|
+
|
238
238
|
# Entity name in Connec!
|
239
239
|
def connec_entity_name
|
240
240
|
raise "Not implemented"
|
@@ -249,4 +249,14 @@ module Maestrano::Connector::Rails::Concerns::Entity
|
|
249
249
|
def mapper_class
|
250
250
|
raise "Not implemented"
|
251
251
|
end
|
252
|
+
|
253
|
+
# Return a string representing the object from a connec! entity hash
|
254
|
+
def object_name_from_connec_entity_hash(entity)
|
255
|
+
raise "Not implemented"
|
256
|
+
end
|
257
|
+
|
258
|
+
# Return a string representing the object from an external entity hash
|
259
|
+
def object_name_from_external_entity_hash(entity)
|
260
|
+
raise "Not implemented"
|
261
|
+
end
|
252
262
|
end
|
@@ -19,4 +19,12 @@
|
|
19
19
|
# raise "Impossible mapping from #{self.entity_name} to #{name}"
|
20
20
|
# end
|
21
21
|
# end
|
22
|
+
|
23
|
+
# def object_name_from_connec_entity_hash(entity)
|
24
|
+
# "#{entity['first_name']} #{entity['last_name']}"
|
25
|
+
# end
|
26
|
+
|
27
|
+
# def object_name_from_external_entity_hash(entity)
|
28
|
+
# "#{entity['FirstName']} #{entity['LastName']}"
|
29
|
+
# end
|
22
30
|
# end
|
@@ -19,4 +19,12 @@
|
|
19
19
|
# raise "Impossible mapping from #{self.entity_name} to #{name}"
|
20
20
|
# end
|
21
21
|
# end
|
22
|
+
|
23
|
+
# def object_name_from_connec_entity_hash(entity)
|
24
|
+
# "#{entity['first_name']} #{entity['last_name']}"
|
25
|
+
# end
|
26
|
+
|
27
|
+
# def object_name_from_external_entity_hash(entity)
|
28
|
+
# "#{entity['FirstName']} #{entity['LastName']}"
|
29
|
+
# end
|
22
30
|
# end
|
@@ -20,4 +20,12 @@
|
|
20
20
|
# raise "Impossible mapping from #{self.entity_name} to #{name}"
|
21
21
|
# end
|
22
22
|
# end
|
23
|
+
|
24
|
+
# def object_name_from_connec_entity_hash(entity)
|
25
|
+
# "#{entity['first_name']} #{entity['last_name']}"
|
26
|
+
# end
|
27
|
+
|
28
|
+
# def object_name_from_external_entity_hash(entity)
|
29
|
+
# "#{entity['FirstName']} #{entity['LastName']}"
|
30
|
+
# end
|
23
31
|
# end
|
@@ -15,6 +15,15 @@
|
|
15
15
|
# def mapper_class
|
16
16
|
# ExampleEntityMapper
|
17
17
|
# end
|
18
|
+
|
19
|
+
# def object_name_from_connec_entity_hash(entity)
|
20
|
+
# "#{entity['first_name']} #{entity['last_name']}"
|
21
|
+
# end
|
22
|
+
|
23
|
+
# def object_name_from_external_entity_hash(entity)
|
24
|
+
# "#{entity['FirstName']} #{entity['LastName']}"
|
25
|
+
# end
|
26
|
+
|
18
27
|
# end
|
19
28
|
|
20
29
|
# class ExampleEntityMapper
|
@@ -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 0.2.
|
5
|
+
# stub: maestrano-connector-rails 0.2.12 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "maestrano-connector-rails"
|
9
|
-
s.version = "0.2.
|
9
|
+
s.version = "0.2.12"
|
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-02
|
14
|
+
s.date = "2016-03-02"
|
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"]
|
@@ -36,6 +36,7 @@ Gem::Specification.new do |s|
|
|
36
36
|
"app/controllers/maestrano/sessions_controller.rb",
|
37
37
|
"app/helpers/maestrano/connector/rails/session_helper.rb",
|
38
38
|
"app/jobs/maestrano/connector/rails/all_synchronizations_job.rb",
|
39
|
+
"app/jobs/maestrano/connector/rails/push_to_connec_job.rb",
|
39
40
|
"app/jobs/maestrano/connector/rails/synchronization_job.rb",
|
40
41
|
"app/models/maestrano/connector/rails/complex_entity.rb",
|
41
42
|
"app/models/maestrano/connector/rails/concerns/entity.rb",
|
@@ -138,6 +139,7 @@ Gem::Specification.new do |s|
|
|
138
139
|
"spec/dummy/public/favicon.ico",
|
139
140
|
"spec/factories.rb",
|
140
141
|
"spec/jobs/all_syncrhonizations_job_spec.rb",
|
142
|
+
"spec/jobs/push_to_connec_job_spec.rb",
|
141
143
|
"spec/jobs/syncrhonization_job_spec.rb",
|
142
144
|
"spec/models/complex_entity_spec.rb",
|
143
145
|
"spec/models/connector_logger_spec.rb",
|
@@ -83,6 +83,9 @@ describe Maestrano::ConnecController, type: :controller do
|
|
83
83
|
before {
|
84
84
|
allow(Maestrano::Connector::Rails::Entity).to receive(:entities_list).and_return(%w(person))
|
85
85
|
class Entities::Person < Maestrano::Connector::Rails::Entity
|
86
|
+
def connec_entity_name
|
87
|
+
'person'
|
88
|
+
end
|
86
89
|
end
|
87
90
|
}
|
88
91
|
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Maestrano::Connector::Rails::PushToConnecJob do
|
4
|
+
let(:organization) { create(:organization) }
|
5
|
+
let(:entity_name1) { 'entity1' }
|
6
|
+
let(:entity_name2) { 'entity2' }
|
7
|
+
before {
|
8
|
+
class Entities::Entity1 < Maestrano::Connector::Rails::Entity
|
9
|
+
def map_to_connec(entity, organization)
|
10
|
+
entity
|
11
|
+
end
|
12
|
+
end
|
13
|
+
allow_any_instance_of(Entities::Entity1).to receive(:push_entities_to_connec)
|
14
|
+
allow_any_instance_of(Entities::Entity1).to receive(:external_entity_name).and_return('ext_entity1')
|
15
|
+
class Entities::Entity2 < Maestrano::Connector::Rails::ComplexEntity
|
16
|
+
end
|
17
|
+
allow_any_instance_of(Entities::Entity2).to receive(:consolidate_and_map_data)
|
18
|
+
allow_any_instance_of(Entities::Entity2).to receive(:push_entities_to_connec)
|
19
|
+
allow_any_instance_of(Entities::Entity2).to receive(:connec_entities_names).and_return(%w())
|
20
|
+
allow_any_instance_of(Entities::Entity2).to receive(:external_entities_names).and_return(%w(sub ll))
|
21
|
+
module Entities::SubEntities end;
|
22
|
+
class Entities::SubEntities::Sub < Maestrano::Connector::Rails::SubEntityBase
|
23
|
+
end
|
24
|
+
allow(Maestrano::Connector::Rails::Entity).to receive(:entities_list).and_return([entity_name1, entity_name2])
|
25
|
+
allow_any_instance_of(Maestrano::Connector::Rails::Entity).to receive(:get_id_from_external_entity_hash).and_return('11')
|
26
|
+
}
|
27
|
+
let(:entity11) { {first_name: 'John'} }
|
28
|
+
let(:entity12) { {first_name: 'Jane'} }
|
29
|
+
let(:entity21) { {job: 'Pizza guy'} }
|
30
|
+
let(:hash) { {'ext_entity1' => [entity11, entity12], 'sub' => [entity21]} }
|
31
|
+
subject { Maestrano::Connector::Rails::PushToConnecJob.perform_now(organization, hash) }
|
32
|
+
|
33
|
+
describe 'with organization sync enabled set to false' do
|
34
|
+
before { organization.update(sync_enabled: false, oauth_uid: 'lala') }
|
35
|
+
|
36
|
+
it 'does nothing' do
|
37
|
+
expect(Maestrano::Connec::Client).to_not receive(:new)
|
38
|
+
subject
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe 'with no oauth uid' do
|
43
|
+
before { organization.update(sync_enabled: true, oauth_uid: nil) }
|
44
|
+
|
45
|
+
it 'does nothing' do
|
46
|
+
expect(Maestrano::Connec::Client).to_not receive(:new)
|
47
|
+
subject
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe 'with sync enabled and an oauth uid' do
|
52
|
+
before { organization.update(sync_enabled: true, oauth_uid: 'lala') }
|
53
|
+
|
54
|
+
describe 'with a non existing entity' do
|
55
|
+
let(:hash) { {'lala' => []} }
|
56
|
+
|
57
|
+
it 'logs a warning' do
|
58
|
+
expect(Rails.logger).to receive(:warn)
|
59
|
+
subject
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe 'with entities in syncrhonized entities' do
|
64
|
+
|
65
|
+
describe 'complex entity' do
|
66
|
+
before { organization.update(synchronized_entities: {:"#{entity_name1}" => false, :"#{entity_name2}" => true})}
|
67
|
+
|
68
|
+
it 'calls consolidate and map data on the complex entity with the right arguments' do
|
69
|
+
expect_any_instance_of(Entities::Entity2).to receive(:consolidate_and_map_data).with({}, {"sub"=>[entity21], "ll"=>[]}, organization, {})
|
70
|
+
expect_any_instance_of(Entities::Entity2).to receive(:push_entities_to_connec)
|
71
|
+
subject
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'does not calls methods on the non complex entity' do
|
75
|
+
expect_any_instance_of(Entities::Entity1).to_not receive(:consolidate_and_map_data)
|
76
|
+
subject
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe 'non complex entity' do
|
81
|
+
before { organization.update(synchronized_entities: {:"#{entity_name1}" => true, :"#{entity_name2}" => false})}
|
82
|
+
|
83
|
+
it 'calls consolidate_and_map_data on the non complex entity with the right arguments' do
|
84
|
+
expect_any_instance_of(Entities::Entity1).to receive(:consolidate_and_map_data).with([], [entity11, entity12], organization, {})
|
85
|
+
expect_any_instance_of(Entities::Entity1).to receive(:push_entities_to_connec)
|
86
|
+
subject
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'does not calls methods on the complex entity' do
|
90
|
+
allow_any_instance_of(Entities::Entity1).to receive(:consolidate_and_map_data)
|
91
|
+
expect_any_instance_of(Entities::Entity2).to_not receive(:consolidate_and_map_data)
|
92
|
+
subject
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -29,8 +29,10 @@ describe Maestrano::Connector::Rails::ComplexEntity do
|
|
29
29
|
let(:connec_name) { 'connec_name' }
|
30
30
|
let(:external_name) { 'external_name' }
|
31
31
|
let(:sub_instance) { Maestrano::Connector::Rails::SubEntityBase.new }
|
32
|
+
let(:human_name) { 'ET' }
|
32
33
|
before {
|
33
34
|
allow(sub_instance).to receive(:map_to).and_return(mapped_entity)
|
35
|
+
allow(sub_instance).to receive(:object_name_from_connec_entity_hash).and_return(human_name)
|
34
36
|
}
|
35
37
|
|
36
38
|
context 'when entity has no idmap' do
|
@@ -185,6 +187,12 @@ describe Maestrano::Connector::Rails::ComplexEntity do
|
|
185
187
|
}
|
186
188
|
|
187
189
|
context 'when entities have no idmaps' do
|
190
|
+
let(:human_name) { 'Jabba' }
|
191
|
+
before {
|
192
|
+
allow_any_instance_of(Entities::SubEntities::ScE1).to receive(:object_name_from_external_entity_hash).and_return(human_name)
|
193
|
+
allow_any_instance_of(Entities::SubEntities::ScE2).to receive(:object_name_from_external_entity_hash).and_return(human_name)
|
194
|
+
}
|
195
|
+
|
188
196
|
it 'creates an idmap for each entity' do
|
189
197
|
expect{
|
190
198
|
subject.consolidate_and_map_data({}, external_hash, organization, opt)
|
data/spec/models/entity_spec.rb
CHANGED
@@ -227,12 +227,20 @@ describe Maestrano::Connector::Rails::Entity do
|
|
227
227
|
|
228
228
|
context 'when entity has no idmap' do
|
229
229
|
let(:entity) { {'id' => id, 'name' => 'John', 'updated_at' => 5.hour.ago } }
|
230
|
+
before {
|
231
|
+
allow(subject).to receive(:object_name_from_connec_entity_hash).and_return('human readable stuff')
|
232
|
+
}
|
230
233
|
|
231
234
|
it { expect{ subject.map_to_external_with_idmap(entity, organization) }.to change{Maestrano::Connector::Rails::IdMap.count}.by(1) }
|
232
235
|
|
233
236
|
it 'returns the entity with its new idmap' do
|
234
237
|
expect(subject.map_to_external_with_idmap(entity, organization)).to eql({entity: mapped_entity, idmap: Maestrano::Connector::Rails::IdMap.last})
|
235
238
|
end
|
239
|
+
|
240
|
+
it 'save the entity name in the idmap' do
|
241
|
+
subject.map_to_external_with_idmap(entity, organization)
|
242
|
+
expect(Maestrano::Connector::Rails::IdMap.last.name).to eql('human readable stuff')
|
243
|
+
end
|
236
244
|
end
|
237
245
|
end
|
238
246
|
end
|
@@ -360,10 +368,20 @@ describe Maestrano::Connector::Rails::Entity do
|
|
360
368
|
}
|
361
369
|
|
362
370
|
context 'when entity has no idmap' do
|
371
|
+
let(:human_name) { 'alien' }
|
372
|
+
before {
|
373
|
+
allow(subject).to receive(:object_name_from_external_entity_hash).and_return(human_name)
|
374
|
+
}
|
375
|
+
|
363
376
|
it 'creates an idmap and returns the mapped entity with its new idmap' do
|
364
377
|
subject.consolidate_and_map_data([], entities, organization)
|
365
378
|
expect(entities).to eql([{entity: mapped_entity, idmap: Maestrano::Connector::Rails::IdMap.last}])
|
366
379
|
end
|
380
|
+
|
381
|
+
it 'save the name in the idmap' do
|
382
|
+
subject.consolidate_and_map_data([], entities, organization)
|
383
|
+
expect(Maestrano::Connector::Rails::IdMap.last.name).to eql(human_name)
|
384
|
+
end
|
367
385
|
end
|
368
386
|
|
369
387
|
context 'when entity has an idmap with a last_push_to_connec more recent than date' do
|
@@ -452,6 +470,14 @@ describe Maestrano::Connector::Rails::Entity do
|
|
452
470
|
describe 'mapper_class' do
|
453
471
|
it { expect{ subject.mapper_class }.to raise_error('Not implemented') }
|
454
472
|
end
|
473
|
+
|
474
|
+
describe 'object_name_from_connec_entity_hash' do
|
475
|
+
it { expect{ subject.object_name_from_connec_entity_hash({}) }.to raise_error('Not implemented') }
|
476
|
+
end
|
477
|
+
|
478
|
+
describe 'object_name_from_external_entity_hash' do
|
479
|
+
it { expect{ subject.object_name_from_external_entity_hash({}) }.to raise_error('Not implemented') }
|
480
|
+
end
|
455
481
|
end
|
456
482
|
|
457
483
|
end
|
@@ -29,6 +29,18 @@ run 'touch Gemfile'
|
|
29
29
|
|
30
30
|
add_source 'https://rubygems.org'
|
31
31
|
|
32
|
+
if yes?("Use JRuby? [y/n]")
|
33
|
+
run 'echo "ruby \'2.2.2\', :engine => \'jruby\', :engine_version => \'9.0.4.0\'" | cat - Gemfile > temp && mv temp Gemfile'
|
34
|
+
gem_group :production do
|
35
|
+
gem 'activerecord-jdbcpostgresql-adapter'
|
36
|
+
end
|
37
|
+
gem_group :test, :develpment do
|
38
|
+
gem 'activerecord-jdbcsqlite3-adapter'
|
39
|
+
end
|
40
|
+
else
|
41
|
+
gem 'sqlite3'
|
42
|
+
end
|
43
|
+
|
32
44
|
gem 'rails', '4.2.4'
|
33
45
|
gem 'turbolinks'
|
34
46
|
gem 'jquery-rails'
|
@@ -39,7 +51,6 @@ gem 'tzinfo-data', platforms: [:mingw, :mswin, :jruby]
|
|
39
51
|
gem 'maestrano-connector-rails'
|
40
52
|
gem 'delayed_job_active_record'
|
41
53
|
|
42
|
-
gem 'sqlite3'
|
43
54
|
|
44
55
|
gem_group :test do
|
45
56
|
gem 'simplecov'
|
@@ -71,7 +82,6 @@ after_bundle do
|
|
71
82
|
RUBY
|
72
83
|
end
|
73
84
|
|
74
|
-
run 'rails g maestrano:initializer'
|
75
85
|
run 'rails g connector:install'
|
76
86
|
run 'bundle exec figaro install'
|
77
87
|
run 'rake railties:install:migrations'
|
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: 0.2.
|
4
|
+
version: 0.2.12
|
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-02
|
11
|
+
date: 2016-03-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: maestrano-rails
|
@@ -204,6 +204,7 @@ files:
|
|
204
204
|
- app/controllers/maestrano/sessions_controller.rb
|
205
205
|
- app/helpers/maestrano/connector/rails/session_helper.rb
|
206
206
|
- app/jobs/maestrano/connector/rails/all_synchronizations_job.rb
|
207
|
+
- app/jobs/maestrano/connector/rails/push_to_connec_job.rb
|
207
208
|
- app/jobs/maestrano/connector/rails/synchronization_job.rb
|
208
209
|
- app/models/maestrano/connector/rails/complex_entity.rb
|
209
210
|
- app/models/maestrano/connector/rails/concerns/entity.rb
|
@@ -306,6 +307,7 @@ files:
|
|
306
307
|
- spec/dummy/public/favicon.ico
|
307
308
|
- spec/factories.rb
|
308
309
|
- spec/jobs/all_syncrhonizations_job_spec.rb
|
310
|
+
- spec/jobs/push_to_connec_job_spec.rb
|
309
311
|
- spec/jobs/syncrhonization_job_spec.rb
|
310
312
|
- spec/models/complex_entity_spec.rb
|
311
313
|
- spec/models/connector_logger_spec.rb
|