forest_liana 2.9.2 → 2.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/forest_liana/mixpanel_controller.rb +27 -0
- data/app/serializers/forest_liana/mixpanel_event_serializer.rb +24 -0
- data/app/serializers/forest_liana/serializer_factory.rb +44 -0
- data/app/services/forest_liana/mixpanel_last_events_getter.rb +87 -0
- data/app/services/forest_liana/schema_adapter.rb +22 -0
- data/config/routes.rb +3 -0
- data/lib/forest_liana.rb +3 -0
- data/lib/forest_liana/bootstraper.rb +72 -0
- data/lib/forest_liana/mixpanel_event.rb +4 -0
- data/lib/forest_liana/version.rb +1 -1
- metadata +6 -6
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/test.log +0 -56094
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b0a1f4647f0e31bc9e84c3ded9ba550c9b3d7fd7
|
4
|
+
data.tar.gz: 0aa2dadfd408b34049411e9945943e127a5b9b8e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fb35fc0d3851ebedf7ebb37739847a09dc6352e3be6b62da28dcda3ca4f758db88795dc98d4a87c0c2b6b66ab0620f5fffcc3b0d3776e3db4d1944cb7b067b2d
|
7
|
+
data.tar.gz: e79eebb6fdecb583d82f4cdc7326845ca0a958ba6044b159fcf5336c5747c0f16ccea010bc700b4e295638fee4a6b458a76198af256ae9273aad4ba009ca7afe
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module ForestLiana
|
2
|
+
class MixpanelController < ForestLiana::ApplicationController
|
3
|
+
def last_events
|
4
|
+
collection_name = params[:collection]
|
5
|
+
mapping = ForestLiana.integrations[:mixpanel][:mapping]
|
6
|
+
mapping_for_current_collection = mapping.find { |item| item.start_with?(collection_name) }
|
7
|
+
field_name = mapping_for_current_collection.split('.')[1]
|
8
|
+
id = params[:id]
|
9
|
+
field_value = collection_name.constantize.find_by('id': id)[field_name]
|
10
|
+
|
11
|
+
getter = ForestLiana::MixpanelLastEventsGetter.new(params)
|
12
|
+
getter.perform(field_name, field_value)
|
13
|
+
|
14
|
+
custom_properties = ForestLiana.integrations[:mixpanel][:custom_properties]
|
15
|
+
MixpanelEventSerializer.attributes(*custom_properties)
|
16
|
+
|
17
|
+
render serializer: nil, json: serialize_models(getter.records, {
|
18
|
+
context: { type: get_serializer_type('mixpanel_events') },
|
19
|
+
count: getter.count,
|
20
|
+
})
|
21
|
+
end
|
22
|
+
|
23
|
+
def get_serializer_type(suffix)
|
24
|
+
"#{params[:collection]}_#{suffix}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module ForestLiana
|
2
|
+
class MixpanelEventSerializer
|
3
|
+
include JSONAPI::Serializer
|
4
|
+
|
5
|
+
attribute :id
|
6
|
+
attribute :event
|
7
|
+
attribute :city
|
8
|
+
attribute :region
|
9
|
+
attribute :timezone
|
10
|
+
attribute :os
|
11
|
+
attribute :osVersion
|
12
|
+
attribute :country
|
13
|
+
attribute :date
|
14
|
+
attribute :browser
|
15
|
+
|
16
|
+
def self_link
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def type
|
21
|
+
@options[:context][:type] || 'mixpanel_events'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -41,6 +41,8 @@ module ForestLiana
|
|
41
41
|
"ForestLiana::ActionSerializer"
|
42
42
|
elsif active_record_class == ForestLiana::Model::Segment
|
43
43
|
"ForestLiana::SegmentSerializer"
|
44
|
+
elsif active_record_class == ForestLiana::MixpanelEvent
|
45
|
+
"ForestLiana::MixpanelEventSerializer"
|
44
46
|
else
|
45
47
|
serializer_name = self.build_serializer_name(active_record_class)
|
46
48
|
"ForestLiana::UserSpace::#{serializer_name}"
|
@@ -109,6 +111,13 @@ module ForestLiana
|
|
109
111
|
end
|
110
112
|
end
|
111
113
|
|
114
|
+
if mixpanel_integration?
|
115
|
+
case attribute_name
|
116
|
+
when :mixpanel_last_events
|
117
|
+
ret[:href] = "/forest/#{ForestLiana.name_for(object.class)}/#{object.id}/mixpanel_last_events"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
112
121
|
if ret[:href].blank?
|
113
122
|
begin
|
114
123
|
if @options[:include].try(:include?, attribute_name.to_s)
|
@@ -151,6 +160,21 @@ module ForestLiana
|
|
151
160
|
false
|
152
161
|
end
|
153
162
|
end
|
163
|
+
|
164
|
+
def mixpanel_integration?
|
165
|
+
mapping = ForestLiana.integrations
|
166
|
+
.try(:[], :mixpanel)
|
167
|
+
.try(:[], :mapping)
|
168
|
+
|
169
|
+
if mapping
|
170
|
+
collection_names = mapping.map do |collection_name_and_field|
|
171
|
+
collection_name_and_field.split('.')[0]
|
172
|
+
end
|
173
|
+
collection_names.include?(object.class.name)
|
174
|
+
else
|
175
|
+
false
|
176
|
+
end
|
177
|
+
end
|
154
178
|
}
|
155
179
|
|
156
180
|
unless @is_smart_collection
|
@@ -248,6 +272,11 @@ module ForestLiana
|
|
248
272
|
serializer.send(:has_many, :stripe_bank_accounts) { }
|
249
273
|
end
|
250
274
|
|
275
|
+
# Mixpanel
|
276
|
+
if has_mixpanel_integration?(active_record_class.name)
|
277
|
+
serializer.send(:has_many, :mixpanel_last_events) { }
|
278
|
+
end
|
279
|
+
|
251
280
|
ForestLiana::SerializerFactory.define_serializer(active_record_class,
|
252
281
|
serializer)
|
253
282
|
|
@@ -287,6 +316,21 @@ module ForestLiana
|
|
287
316
|
end
|
288
317
|
end
|
289
318
|
|
319
|
+
def has_mixpanel_integration?(collection_name)
|
320
|
+
mapping = ForestLiana.integrations
|
321
|
+
.try(:[], :mixpanel)
|
322
|
+
.try(:[], :mapping)
|
323
|
+
|
324
|
+
if mapping
|
325
|
+
collection_names = mapping.map do |collection_name_and_field|
|
326
|
+
collection_name_and_field.split('.')[0]
|
327
|
+
end
|
328
|
+
collection_names.include?(collection_name)
|
329
|
+
else
|
330
|
+
false
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
290
334
|
def serializer_association(association)
|
291
335
|
case association.macro
|
292
336
|
when :has_one, :belongs_to
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module ForestLiana
|
2
|
+
class MixpanelLastEventsGetter < IntegrationBaseGetter
|
3
|
+
attr_accessor :record
|
4
|
+
|
5
|
+
def initialize(params)
|
6
|
+
@params = params
|
7
|
+
api_secret = ForestLiana.integrations[:mixpanel][:api_secret]
|
8
|
+
@custom_properties = ForestLiana.integrations[:mixpanel][:custom_properties]
|
9
|
+
@mixpanel = Mixpanel::Client.new(api_secret: api_secret)
|
10
|
+
end
|
11
|
+
|
12
|
+
def perform(field_name, field_value)
|
13
|
+
result = @mixpanel.request(
|
14
|
+
'jql',
|
15
|
+
script: "function main() {
|
16
|
+
return People().filter(function (user) {
|
17
|
+
return user.properties.$email == '#{field_value}';
|
18
|
+
});
|
19
|
+
}"
|
20
|
+
)
|
21
|
+
|
22
|
+
if result.length == 0
|
23
|
+
@records = []
|
24
|
+
return
|
25
|
+
end
|
26
|
+
|
27
|
+
from_date = (DateTime.now << 6).strftime("%Y-%m-%d")
|
28
|
+
to_date = DateTime.now.strftime("%Y-%m-%d")
|
29
|
+
distinct_id = result[0]['distinct_id']
|
30
|
+
|
31
|
+
result = @mixpanel.request(
|
32
|
+
'stream/query',
|
33
|
+
from_date: from_date,
|
34
|
+
to_date: to_date,
|
35
|
+
distinct_ids: [distinct_id],
|
36
|
+
limit: 100
|
37
|
+
)
|
38
|
+
|
39
|
+
if result['status'] != 'ok'
|
40
|
+
FOREST_LOGGER.error "Cannot retrieve the Mixpanel last events"
|
41
|
+
@records = []
|
42
|
+
return
|
43
|
+
end
|
44
|
+
|
45
|
+
if result.length == 0
|
46
|
+
@records = []
|
47
|
+
return
|
48
|
+
end
|
49
|
+
|
50
|
+
@records = process_result(result['results']['events'])
|
51
|
+
end
|
52
|
+
|
53
|
+
def process_result(events)
|
54
|
+
events.reverse.map { |event|
|
55
|
+
properties = event['properties']
|
56
|
+
|
57
|
+
new_event = {
|
58
|
+
'id' => SecureRandom.uuid,
|
59
|
+
'event' => event['event'],
|
60
|
+
'city' => properties['$city'],
|
61
|
+
'region' => properties['$region'],
|
62
|
+
'timezone' => properties['$timezone'],
|
63
|
+
'os' => properties['$os'],
|
64
|
+
'osVersion' => properties['$os_version'],
|
65
|
+
'country' => properties['mp_country_code'],
|
66
|
+
'browser' => properties['browser'],
|
67
|
+
}
|
68
|
+
|
69
|
+
time = properties['time'].to_s
|
70
|
+
new_event['date'] = DateTime.strptime(time,'%s').strftime("%Y-%m-%dT%H:%M:%S%z")
|
71
|
+
|
72
|
+
custom_attributes = event['properties'].select { |key, _| @custom_properties.include? key }
|
73
|
+
new_event = new_event.merge(custom_attributes)
|
74
|
+
|
75
|
+
ForestLiana::MixpanelEvent.new(new_event)
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
def records
|
80
|
+
@records
|
81
|
+
end
|
82
|
+
|
83
|
+
def count
|
84
|
+
@records.count
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -179,6 +179,28 @@ module ForestLiana
|
|
179
179
|
end
|
180
180
|
end
|
181
181
|
|
182
|
+
# NOTICE: Add Mixpanel field
|
183
|
+
mixpanel_mapping = ForestLiana.integrations
|
184
|
+
.try(:[], :mixpanel)
|
185
|
+
.try(:[], :mapping)
|
186
|
+
|
187
|
+
if mixpanel_mapping && mixpanel_mapping
|
188
|
+
.select { |mapping| mapping.split('.')[0] == @model.name }
|
189
|
+
.size > 0
|
190
|
+
|
191
|
+
model_name = ForestLiana.name_for(@model)
|
192
|
+
|
193
|
+
collection.fields << {
|
194
|
+
field: :mixpanel_last_events,
|
195
|
+
type: ['String'],
|
196
|
+
reference: "#{model_name}_mixpanel_events.id",
|
197
|
+
column: nil,
|
198
|
+
'is-filterable': false,
|
199
|
+
'display-name': 'Last events',
|
200
|
+
integration: 'mixpanel',
|
201
|
+
}
|
202
|
+
end
|
203
|
+
|
182
204
|
# NOTICE: Add Paperclip url attributes
|
183
205
|
if @model.respond_to?(:attachment_definitions)
|
184
206
|
@model.attachment_definitions.each do |key, value|
|
data/config/routes.rb
CHANGED
@@ -39,6 +39,9 @@ ForestLiana::Engine.routes.draw do
|
|
39
39
|
get ':collection/:id/intercom_attributes' => 'intercom#attributes'
|
40
40
|
get '(*collection)_intercom_conversations/:conversation_id' => 'intercom#conversation'
|
41
41
|
|
42
|
+
# Mixpanel Integration
|
43
|
+
get ':collection/:id/mixpanel_last_events' => 'mixpanel#last_events'
|
44
|
+
|
42
45
|
# Devise support
|
43
46
|
post '/actions/change-password' => 'devise#change_password'
|
44
47
|
|
data/lib/forest_liana.rb
CHANGED
@@ -113,6 +113,17 @@ module ForestLiana
|
|
113
113
|
'Please go to https://doc.forestadmin.com for more information.'
|
114
114
|
end
|
115
115
|
end
|
116
|
+
|
117
|
+
if mixpanel_integration?
|
118
|
+
if mixpanel_integration_valid?
|
119
|
+
ForestLiana.integrations[:mixpanel][:mapping] =
|
120
|
+
cast_to_array(ForestLiana.integrations[:mixpanel][:mapping])
|
121
|
+
@integration_mixpanel_valid = true
|
122
|
+
else
|
123
|
+
FOREST_LOGGER.error 'Cannot setup properly your Mixpanel integration. ' \
|
124
|
+
'Please go to https://doc.forestadmin.com for more information.'
|
125
|
+
end
|
126
|
+
end
|
116
127
|
end
|
117
128
|
|
118
129
|
def namespace_duplicated_models
|
@@ -149,6 +160,12 @@ module ForestLiana
|
|
149
160
|
setup_intercom_integration collection_name
|
150
161
|
end
|
151
162
|
end
|
163
|
+
|
164
|
+
if @integration_mixpanel_valid
|
165
|
+
ForestLiana.integrations[:mixpanel][:mapping].each do |collection_name|
|
166
|
+
setup_mixpanel_integration collection_name
|
167
|
+
end
|
168
|
+
end
|
152
169
|
end
|
153
170
|
|
154
171
|
def require_lib_forest_liana
|
@@ -522,6 +539,61 @@ module ForestLiana
|
|
522
539
|
is_deprecated
|
523
540
|
end
|
524
541
|
|
542
|
+
def setup_mixpanel_integration(collection_name_and_field)
|
543
|
+
collection_name = collection_name_and_field.split('.')[0]
|
544
|
+
model_name = ForestLiana.name_for(collection_name.constantize)
|
545
|
+
collection_display_name = model_name.capitalize
|
546
|
+
|
547
|
+
field_attributes = { 'is-filterable': false , 'is-virtual': true, 'is-sortable': false }
|
548
|
+
|
549
|
+
fields = [
|
550
|
+
{ field: :id, type: 'String' },
|
551
|
+
{ field: :event, type: 'String' },
|
552
|
+
{ field: :date, type: 'Date' },
|
553
|
+
{ field: :city, type: 'String' },
|
554
|
+
{ field: :region, type: 'String' },
|
555
|
+
{ field: :country, type: 'String' },
|
556
|
+
{ field: :timezone, type: 'String' },
|
557
|
+
{ field: :os, type: 'String' },
|
558
|
+
{ field: :osVersion, type: 'String' },
|
559
|
+
{ field: :browser, type: 'String' },
|
560
|
+
{ field: :browserVersion, type: 'String' },
|
561
|
+
]
|
562
|
+
|
563
|
+
fields = fields.map { |field| field.merge(field_attributes) }
|
564
|
+
|
565
|
+
custom_properties = ForestLiana.integrations[:mixpanel][:custom_properties]
|
566
|
+
custom_properties = custom_properties.map { |property|
|
567
|
+
{ field: property.to_sym, type: 'String' }.merge(field_attributes)
|
568
|
+
}
|
569
|
+
|
570
|
+
fields = fields.concat(custom_properties)
|
571
|
+
|
572
|
+
ForestLiana.apimap << ForestLiana::Model::Collection.new({
|
573
|
+
name: "#{model_name}_mixpanel_events",
|
574
|
+
display_name: "#{collection_display_name} Events",
|
575
|
+
icon: 'mixpanel',
|
576
|
+
integration: 'mixpanel',
|
577
|
+
is_virtual: true,
|
578
|
+
is_read_only: true,
|
579
|
+
only_for_relationships: true,
|
580
|
+
pagination_type: 'cursor',
|
581
|
+
fields: fields
|
582
|
+
})
|
583
|
+
end
|
584
|
+
|
585
|
+
def mixpanel_integration?
|
586
|
+
ForestLiana.integrations
|
587
|
+
.try(:[], :mixpanel)
|
588
|
+
.present?
|
589
|
+
end
|
590
|
+
|
591
|
+
def mixpanel_integration_valid?
|
592
|
+
integration = ForestLiana.integrations.try(:[], :mixpanel)
|
593
|
+
integration.present? && integration.has_key?(:api_secret) &&
|
594
|
+
integration.has_key?(:mapping)
|
595
|
+
end
|
596
|
+
|
525
597
|
def forest_url
|
526
598
|
ENV['FOREST_URL'] || 'https://api.forestadmin.com';
|
527
599
|
end
|
data/lib/forest_liana/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: forest_liana
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sandro Munda
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-07-
|
11
|
+
date: 2018-07-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -144,6 +144,7 @@ files:
|
|
144
144
|
- app/controllers/forest_liana/base_controller.rb
|
145
145
|
- app/controllers/forest_liana/devise_controller.rb
|
146
146
|
- app/controllers/forest_liana/intercom_controller.rb
|
147
|
+
- app/controllers/forest_liana/mixpanel_controller.rb
|
147
148
|
- app/controllers/forest_liana/resources_controller.rb
|
148
149
|
- app/controllers/forest_liana/router.rb
|
149
150
|
- app/controllers/forest_liana/sessions_controller.rb
|
@@ -161,6 +162,7 @@ files:
|
|
161
162
|
- app/serializers/forest_liana/collection_serializer.rb
|
162
163
|
- app/serializers/forest_liana/intercom_attribute_serializer.rb
|
163
164
|
- app/serializers/forest_liana/intercom_conversation_serializer.rb
|
165
|
+
- app/serializers/forest_liana/mixpanel_event_serializer.rb
|
164
166
|
- app/serializers/forest_liana/segment_serializer.rb
|
165
167
|
- app/serializers/forest_liana/serializer_factory.rb
|
166
168
|
- app/serializers/forest_liana/session_serializer.rb
|
@@ -186,6 +188,7 @@ files:
|
|
186
188
|
- app/services/forest_liana/intercom_conversations_getter.rb
|
187
189
|
- app/services/forest_liana/line_stat_getter.rb
|
188
190
|
- app/services/forest_liana/live_query_checker.rb
|
191
|
+
- app/services/forest_liana/mixpanel_last_events_getter.rb
|
189
192
|
- app/services/forest_liana/operator_date_interval_parser.rb
|
190
193
|
- app/services/forest_liana/operator_value_parser.rb
|
191
194
|
- app/services/forest_liana/permissions_checker.rb
|
@@ -223,6 +226,7 @@ files:
|
|
223
226
|
- lib/forest_liana/bootstraper.rb
|
224
227
|
- lib/forest_liana/collection.rb
|
225
228
|
- lib/forest_liana/engine.rb
|
229
|
+
- lib/forest_liana/mixpanel_event.rb
|
226
230
|
- lib/forest_liana/version.rb
|
227
231
|
- lib/generators/forest_liana/install_generator.rb
|
228
232
|
- test/dummy/README.rdoc
|
@@ -291,8 +295,6 @@ files:
|
|
291
295
|
- test/dummy/db/migrate/20160628173505_add_timestamps.rb
|
292
296
|
- test/dummy/db/migrate/20170614141921_create_serialize_field.rb
|
293
297
|
- test/dummy/db/schema.rb
|
294
|
-
- test/dummy/db/test.sqlite3
|
295
|
-
- test/dummy/log/test.log
|
296
298
|
- test/dummy/public/404.html
|
297
299
|
- test/dummy/public/422.html
|
298
300
|
- test/dummy/public/500.html
|
@@ -391,7 +393,6 @@ test_files:
|
|
391
393
|
- test/dummy/public/500.html
|
392
394
|
- test/dummy/public/404.html
|
393
395
|
- test/dummy/db/schema.rb
|
394
|
-
- test/dummy/db/test.sqlite3
|
395
396
|
- test/dummy/db/migrate/20150608133038_create_belongs_to_field.rb
|
396
397
|
- test/dummy/db/migrate/20150608130516_create_date_field.rb
|
397
398
|
- test/dummy/db/migrate/20160627172951_create_tree.rb
|
@@ -410,7 +411,6 @@ test_files:
|
|
410
411
|
- test/dummy/db/migrate/20150608131603_create_decimal_field.rb
|
411
412
|
- test/dummy/db/migrate/20150623115554_create_has_many_class_name_field.rb
|
412
413
|
- test/dummy/db/migrate/20150616150629_create_polymorphic_field.rb
|
413
|
-
- test/dummy/log/test.log
|
414
414
|
- test/dummy/README.rdoc
|
415
415
|
- test/integration/navigation_test.rb
|
416
416
|
- test/forest_liana_test.rb
|