forest_liana 1.1.22 → 1.1.23
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/intercom_controller.rb +17 -0
- data/app/controllers/forest_liana/stripe_controller.rb +0 -1
- data/app/models/forest_liana/model/collection.rb +3 -1
- data/app/serializers/forest_liana/collection_serializer.rb +4 -0
- data/app/serializers/forest_liana/intercom_attribute_serializer.rb +85 -0
- data/app/serializers/forest_liana/intercom_conversation_serializer.rb +46 -0
- data/app/serializers/forest_liana/serializer_factory.rb +67 -13
- data/app/services/forest_liana/intercom_attributes_getter.rb +44 -0
- data/app/services/forest_liana/intercom_conversations_getter.rb +87 -0
- data/app/services/forest_liana/schema_adapter.rb +48 -0
- data/app/services/forest_liana/stripe_cards_getter.rb +17 -16
- data/app/services/forest_liana/stripe_invoices_getter.rb +19 -21
- data/app/services/forest_liana/stripe_payments_getter.rb +19 -21
- data/config/initializers/time_formats.rb +1 -0
- data/config/routes.rb +7 -1
- data/lib/forest_liana/bootstraper.rb +228 -0
- data/lib/forest_liana/engine.rb +6 -55
- data/lib/forest_liana/version.rb +1 -1
- metadata +37 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1667b0443d65ca46628d3b67e05151ada194709e
|
4
|
+
data.tar.gz: 06ff809ebc4268988858885178755da79bca03e7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cd67e80fa3f3c6cb3f1f179b754805e255ebf69bc2e5551c38e8e1a3859714beabb5a7b9319f188260b69a5559bb8795c0a4ffa6982888dba6690c2fdcef56b0
|
7
|
+
data.tar.gz: 65eca07f4f24cc212e37f6fd4c8350bfc257a6364ea1f8df0b5384bfa679a0ba7ea453fcd24452c375c60d5ff503aab7a9ddf2ac01a46da8af57e764e6fde0f7
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ForestLiana
|
2
|
+
class IntercomController < ForestLiana::ApplicationController
|
3
|
+
def user_conversations
|
4
|
+
getter = IntercomConversationsGetter.new(params)
|
5
|
+
getter.perform
|
6
|
+
|
7
|
+
render json: serialize_models(getter.records, { count: getter.count })
|
8
|
+
end
|
9
|
+
|
10
|
+
def attributes
|
11
|
+
getter = IntercomAttributesGetter.new(params)
|
12
|
+
getter.perform
|
13
|
+
|
14
|
+
render json: serialize_model(getter.records)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -4,10 +4,12 @@ class ForestLiana::Model::Collection
|
|
4
4
|
include ActiveModel::Serialization
|
5
5
|
extend ActiveModel::Naming
|
6
6
|
|
7
|
-
attr_accessor :name, :fields, :actions
|
7
|
+
attr_accessor :name, :fields, :actions, :only_for_relationships, :is_virtual,
|
8
|
+
:is_read_only, :is_searchable
|
8
9
|
|
9
10
|
def initialize(attributes = {})
|
10
11
|
@actions = []
|
12
|
+
@is_searchable = true
|
11
13
|
|
12
14
|
attributes.each do |name, value|
|
13
15
|
send("#{name}=", value)
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module ForestLiana
|
2
|
+
class IntercomAttributeSerializer
|
3
|
+
include JSONAPI::Serializer
|
4
|
+
|
5
|
+
attribute :session_count
|
6
|
+
attribute :last_seen_ip
|
7
|
+
|
8
|
+
attribute :created_at do
|
9
|
+
object.created_at.utc.try(:iso8601)
|
10
|
+
end
|
11
|
+
|
12
|
+
attribute :updated_at do
|
13
|
+
object.updated_at.utc.try(:iso8601)
|
14
|
+
end
|
15
|
+
|
16
|
+
attribute :signed_up_at do
|
17
|
+
object.signed_up_at.utc.try(:iso8601)
|
18
|
+
end
|
19
|
+
|
20
|
+
attribute :last_request_at do
|
21
|
+
object.last_request_at.utc.try(:iso8601)
|
22
|
+
end
|
23
|
+
|
24
|
+
attribute :country do
|
25
|
+
object.location_data.country_name
|
26
|
+
end
|
27
|
+
|
28
|
+
attribute :city do
|
29
|
+
object.location_data.city_name
|
30
|
+
end
|
31
|
+
|
32
|
+
attribute :user_agent do
|
33
|
+
object.user_agent_data
|
34
|
+
end
|
35
|
+
|
36
|
+
attribute :companies do
|
37
|
+
object.companies.map(&:name)
|
38
|
+
end
|
39
|
+
|
40
|
+
attribute :segments do
|
41
|
+
object.segments.map(&:name)
|
42
|
+
end
|
43
|
+
|
44
|
+
attribute :tags do
|
45
|
+
object.tags.map(&:name)
|
46
|
+
end
|
47
|
+
|
48
|
+
attribute :browser do
|
49
|
+
useragent = UserAgent.parse(object.user_agent_data)
|
50
|
+
"#{useragent.try(:browser)} #{useragent.try(:version)}"
|
51
|
+
end
|
52
|
+
|
53
|
+
attribute :platform do
|
54
|
+
UserAgent.parse(object.user_agent_data).try(:platform)
|
55
|
+
end
|
56
|
+
|
57
|
+
attribute :geoloc do
|
58
|
+
[object.location_data.latitude, object.location_data.longitude]
|
59
|
+
end
|
60
|
+
|
61
|
+
def self_link
|
62
|
+
"/forest#{super}"
|
63
|
+
end
|
64
|
+
|
65
|
+
def type
|
66
|
+
'intercom-attributes'
|
67
|
+
end
|
68
|
+
|
69
|
+
def format_name(attribute_name)
|
70
|
+
attribute_name.to_s
|
71
|
+
end
|
72
|
+
|
73
|
+
def unformat_name(attribute_name)
|
74
|
+
attribute_name.to_s.underscore
|
75
|
+
end
|
76
|
+
|
77
|
+
def relationship_self_link(attribute_name)
|
78
|
+
nil
|
79
|
+
end
|
80
|
+
|
81
|
+
def relationship_related_link(attribute_name)
|
82
|
+
nil
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module ForestLiana
|
2
|
+
class IntercomConversationSerializer
|
3
|
+
include JSONAPI::Serializer
|
4
|
+
|
5
|
+
attribute :created_at
|
6
|
+
attribute :updated_at
|
7
|
+
attribute :open
|
8
|
+
attribute :read
|
9
|
+
|
10
|
+
attribute :subject do
|
11
|
+
object.conversation_message.subject
|
12
|
+
end
|
13
|
+
|
14
|
+
attribute :body do
|
15
|
+
[object.conversation_message.body, object.link]
|
16
|
+
end
|
17
|
+
|
18
|
+
attribute :assignee do
|
19
|
+
object.assignee.try(:email)
|
20
|
+
end
|
21
|
+
|
22
|
+
def self_link
|
23
|
+
"/forest#{super}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def type
|
27
|
+
'intercom-conversations'
|
28
|
+
end
|
29
|
+
|
30
|
+
def format_name(attribute_name)
|
31
|
+
attribute_name.to_s
|
32
|
+
end
|
33
|
+
|
34
|
+
def unformat_name(attribute_name)
|
35
|
+
attribute_name.to_s.underscore
|
36
|
+
end
|
37
|
+
|
38
|
+
def relationship_self_link(attribute_name)
|
39
|
+
nil
|
40
|
+
end
|
41
|
+
|
42
|
+
def relationship_related_link(attribute_name)
|
43
|
+
nil
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -14,7 +14,11 @@ module ForestLiana
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def self.get_serializer_name(active_record_class)
|
17
|
-
if active_record_class ==
|
17
|
+
if active_record_class == ::Intercom::Conversation
|
18
|
+
"ForestLiana::IntercomConversationSerializer"
|
19
|
+
elsif active_record_class == ::Intercom::User
|
20
|
+
"ForestLiana::IntercomAttributeSerializer"
|
21
|
+
elsif active_record_class == Stripe::Charge
|
18
22
|
"ForestLiana::StripePaymentSerializer"
|
19
23
|
elsif active_record_class == Stripe::Card
|
20
24
|
"ForestLiana::StripeCardSerializer"
|
@@ -64,22 +68,58 @@ module ForestLiana
|
|
64
68
|
def relationship_related_link(attribute_name)
|
65
69
|
ret = {}
|
66
70
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
ret[:
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
71
|
+
if intercom_integration?
|
72
|
+
case attribute_name
|
73
|
+
when :intercom_conversations
|
74
|
+
ret[:href] = "/forest/#{object.class.table_name}/#{object.id}/intercom_conversations"
|
75
|
+
when :intercom_attributes
|
76
|
+
ret[:href] = "/forest/#{object.class.table_name}/#{object.id}/intercom_attributes"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
if stripe_integration?
|
81
|
+
case attribute_name
|
82
|
+
when :stripe_payments
|
83
|
+
ret[:href] = "/forest/#{object.class.table_name}/#{object.id}/stripe_payments"
|
84
|
+
when :stripe_invoices
|
85
|
+
ret[:href] = "/forest/#{object.class.table_name}/#{object.id}/stripe_invoices"
|
86
|
+
when :stripe_cards
|
87
|
+
ret[:href] = "/forest/#{object.class.table_name}/#{object.id}/stripe_cards"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
if ret[:href].blank?
|
92
|
+
relationship_records = object.send(attribute_name)
|
93
|
+
|
94
|
+
if relationship_records.respond_to?(:each)
|
95
|
+
if Rails::VERSION::MAJOR == 4
|
96
|
+
ret[:href] = "/forest/#{object.class.table_name}/#{object.id}/#{attribute_name}"
|
97
|
+
ret[:meta] = { count: relationship_records.distinct.count }
|
98
|
+
else
|
99
|
+
ret[:href] = "/forest/#{object.class.table_name}/#{object.id}/#{attribute_name}"
|
100
|
+
ret[:meta] = {
|
101
|
+
count: relationship_records.count(:id, distinct: true)
|
102
|
+
}
|
103
|
+
end
|
78
104
|
end
|
79
105
|
end
|
80
106
|
|
81
107
|
ret
|
82
108
|
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
def intercom_integration?
|
113
|
+
object.class.name == ForestLiana.integrations
|
114
|
+
.try(:[], :intercom)
|
115
|
+
.try(:[], :user_collection)
|
116
|
+
end
|
117
|
+
|
118
|
+
def stripe_integration?
|
119
|
+
object.class.name == ForestLiana.integrations
|
120
|
+
.try(:[], :stripe)
|
121
|
+
.try(:[], :user_collection)
|
122
|
+
end
|
83
123
|
}
|
84
124
|
|
85
125
|
attributes(active_record_class).each do |attr|
|
@@ -97,6 +137,21 @@ module ForestLiana
|
|
97
137
|
serializer.send(serializer_association(a), a.name)
|
98
138
|
end
|
99
139
|
|
140
|
+
# Intercom
|
141
|
+
if active_record_class.name == ForestLiana.integrations
|
142
|
+
.try(:[], :intercom).try(:[], :user_collection)
|
143
|
+
serializer.send(:has_many, :intercom_conversations) { }
|
144
|
+
serializer.send(:has_many, :intercom_attributes) { }
|
145
|
+
end
|
146
|
+
|
147
|
+
# Stripe
|
148
|
+
if active_record_class.name == ForestLiana.integrations
|
149
|
+
.try(:[], :stripe).try(:[], :user_collection)
|
150
|
+
serializer.send(:has_many, :stripe_payments) { }
|
151
|
+
serializer.send(:has_many, :stripe_invoices) { }
|
152
|
+
serializer.send(:has_many, :stripe_cards) { }
|
153
|
+
end
|
154
|
+
|
100
155
|
SerializerFactory.define_serializer(active_record_class, serializer)
|
101
156
|
|
102
157
|
serializer
|
@@ -130,6 +185,5 @@ module ForestLiana
|
|
130
185
|
def foreign_keys(active_record_class)
|
131
186
|
SchemaUtils.associations(active_record_class).map(&:foreign_key)
|
132
187
|
end
|
133
|
-
|
134
188
|
end
|
135
189
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module ForestLiana
|
2
|
+
class IntercomAttributesGetter
|
3
|
+
attr_accessor :records
|
4
|
+
|
5
|
+
def initialize(params)
|
6
|
+
@params = params
|
7
|
+
@intercom = ::Intercom::Client.new(
|
8
|
+
app_id: ForestLiana.integrations[:intercom][:app_id],
|
9
|
+
api_key: ForestLiana.integrations[:intercom][:api_key])
|
10
|
+
end
|
11
|
+
|
12
|
+
def count
|
13
|
+
@records.count
|
14
|
+
end
|
15
|
+
|
16
|
+
def perform
|
17
|
+
resource = user_collection.find(@params[:id])
|
18
|
+
|
19
|
+
begin
|
20
|
+
user = @intercom.users.find(email: resource.email)
|
21
|
+
|
22
|
+
user.segments = user.segments.map do |segment|
|
23
|
+
@intercom.segments.find(id: segment.id)
|
24
|
+
end
|
25
|
+
|
26
|
+
@records = user
|
27
|
+
rescue Intercom::ResourceNotFound
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def user_collection
|
34
|
+
ForestLiana.integrations
|
35
|
+
.try(:[], :intercom)
|
36
|
+
.try(:[], :user_collection)
|
37
|
+
.try(:constantize)
|
38
|
+
end
|
39
|
+
|
40
|
+
def user_collection?
|
41
|
+
user_collection.present?
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module ForestLiana
|
2
|
+
class IntercomConversationsGetter
|
3
|
+
def initialize(params)
|
4
|
+
@params = params
|
5
|
+
@app_id = ForestLiana.integrations[:intercom][:app_id]
|
6
|
+
@api_key = ForestLiana.integrations[:intercom][:api_key]
|
7
|
+
|
8
|
+
@intercom = ::Intercom::Client.new(app_id: @app_id, api_key: @api_key)
|
9
|
+
end
|
10
|
+
|
11
|
+
def count
|
12
|
+
@records.count
|
13
|
+
end
|
14
|
+
|
15
|
+
def records
|
16
|
+
@records[pagination].map do |conversation|
|
17
|
+
if conversation.assignee.is_a?(::Intercom::Admin)
|
18
|
+
admins = @intercom.admins.all.detect(id: conversation.assignee.id)
|
19
|
+
conversation.assignee = admins.first
|
20
|
+
end
|
21
|
+
|
22
|
+
conversation.link = link(conversation)
|
23
|
+
|
24
|
+
conversation
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def perform
|
29
|
+
begin
|
30
|
+
resource = user_collection.find(@params[:id])
|
31
|
+
@records = @intercom.conversations.find_all(
|
32
|
+
email: resource.email,
|
33
|
+
type: 'user',
|
34
|
+
display_as: 'plaintext',
|
35
|
+
).entries
|
36
|
+
rescue Intercom::ResourceNotFound
|
37
|
+
@records = []
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def user_collection
|
44
|
+
ForestLiana.integrations
|
45
|
+
.try(:[], :intercom)
|
46
|
+
.try(:[], :user_collection)
|
47
|
+
.try(:constantize)
|
48
|
+
end
|
49
|
+
|
50
|
+
def user_collection?
|
51
|
+
user_collection.present?
|
52
|
+
end
|
53
|
+
|
54
|
+
def link(conversation)
|
55
|
+
"#{@intercom.base_url}/a/apps/#{@app_id}/inbox/all/conversations/#{conversation.id}"
|
56
|
+
end
|
57
|
+
|
58
|
+
def pagination
|
59
|
+
offset..(offset + limit - 1)
|
60
|
+
end
|
61
|
+
|
62
|
+
def offset
|
63
|
+
return 0 unless pagination?
|
64
|
+
|
65
|
+
number = @params[:page][:number]
|
66
|
+
if number && number.to_i > 0
|
67
|
+
(number.to_i - 1) * limit
|
68
|
+
else
|
69
|
+
0
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def limit
|
74
|
+
return 10 unless pagination?
|
75
|
+
|
76
|
+
if @params[:page][:size]
|
77
|
+
@params[:page][:size].to_i
|
78
|
+
else
|
79
|
+
10
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def pagination?
|
84
|
+
@params[:page] && @params[:page][:number]
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -23,6 +23,54 @@ module ForestLiana
|
|
23
23
|
@collection.fields << get_schema_for_column(column)
|
24
24
|
end
|
25
25
|
|
26
|
+
# Intercom
|
27
|
+
if ForestLiana.integrations.try(:[], :intercom)
|
28
|
+
.try(:[], :user_collection) == @model.name
|
29
|
+
@collection.fields << {
|
30
|
+
field: :intercom_conversations,
|
31
|
+
type: ['String'],
|
32
|
+
reference: 'intercom_conversations.id',
|
33
|
+
column: nil,
|
34
|
+
is_searchable: false
|
35
|
+
}
|
36
|
+
|
37
|
+
@collection.fields << {
|
38
|
+
field: :intercom_attributes,
|
39
|
+
type: 'String',
|
40
|
+
reference: 'intercom_attributes.id',
|
41
|
+
column: nil,
|
42
|
+
is_searchable: false
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
# Stripe
|
47
|
+
if ForestLiana.integrations.try(:[], :stripe)
|
48
|
+
.try(:[], :user_collection) == @model.name
|
49
|
+
@collection.fields << {
|
50
|
+
field: :stripe_payments,
|
51
|
+
type: ['String'],
|
52
|
+
reference: 'stripe_payments.id',
|
53
|
+
column: nil,
|
54
|
+
is_searchable: false
|
55
|
+
}
|
56
|
+
|
57
|
+
@collection.fields << {
|
58
|
+
field: :stripe_invoices,
|
59
|
+
type: ['String'],
|
60
|
+
reference: 'stripe_invoices.id',
|
61
|
+
column: nil,
|
62
|
+
is_searchable: false
|
63
|
+
}
|
64
|
+
|
65
|
+
@collection.fields << {
|
66
|
+
field: :stripe_cards,
|
67
|
+
type: ['String'],
|
68
|
+
reference: 'stripe_cards.id',
|
69
|
+
column: nil,
|
70
|
+
is_searchable: false
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
26
74
|
# Paperclip url attribute
|
27
75
|
if @model.respond_to?(:attachment_definitions)
|
28
76
|
@model.attachment_definitions.each do |key, value|
|
@@ -4,7 +4,6 @@ module ForestLiana
|
|
4
4
|
|
5
5
|
def initialize(params, secret_key, reference)
|
6
6
|
@params = params
|
7
|
-
@reference_model, @reference_field = reference_model(reference)
|
8
7
|
Stripe.api_key = ForestLiana.integrations[:stripe][:api_key]
|
9
8
|
end
|
10
9
|
|
@@ -16,8 +15,8 @@ module ForestLiana
|
|
16
15
|
params = { limit: limit, offset: offset, object: 'card' }
|
17
16
|
params['include[]'] = 'total_count'
|
18
17
|
|
19
|
-
resource =
|
20
|
-
customer = resource[
|
18
|
+
resource = user_collection.find(@params[:id])
|
19
|
+
customer = resource[user_field]
|
21
20
|
|
22
21
|
if customer.blank?
|
23
22
|
@records = []
|
@@ -35,24 +34,13 @@ module ForestLiana
|
|
35
34
|
|
36
35
|
@records = @cards.data.map do |d|
|
37
36
|
query = {}
|
38
|
-
query[
|
39
|
-
d.customer =
|
37
|
+
query[user_field] = d.customer
|
38
|
+
d.customer = user_collection.find_by(query)
|
40
39
|
|
41
40
|
d
|
42
41
|
end
|
43
42
|
end
|
44
43
|
|
45
|
-
def reference_model(reference)
|
46
|
-
resource_name, reference_field = reference.split('.')
|
47
|
-
reference_model = SchemaUtils.find_model_from_table_name(resource_name)
|
48
|
-
|
49
|
-
[reference_model, reference_field]
|
50
|
-
end
|
51
|
-
|
52
|
-
def reference_model_id
|
53
|
-
@params["#{@reference_model.table_name.singularize()}Id"]
|
54
|
-
end
|
55
|
-
|
56
44
|
def offset
|
57
45
|
return 0 unless pagination?
|
58
46
|
|
@@ -77,5 +65,18 @@ module ForestLiana
|
|
77
65
|
def pagination?
|
78
66
|
@params[:page] && @params[:page][:number]
|
79
67
|
end
|
68
|
+
|
69
|
+
def user_collection
|
70
|
+
ForestLiana.integrations
|
71
|
+
.try(:[], :stripe)
|
72
|
+
.try(:[], :user_collection)
|
73
|
+
.try(:constantize)
|
74
|
+
end
|
75
|
+
|
76
|
+
def user_field
|
77
|
+
ForestLiana.integrations
|
78
|
+
.try(:[], :stripe)
|
79
|
+
.try(:[], :user_field)
|
80
|
+
end
|
80
81
|
end
|
81
82
|
end
|
@@ -4,7 +4,6 @@ module ForestLiana
|
|
4
4
|
|
5
5
|
def initialize(params, secret_key, reference)
|
6
6
|
@params = params
|
7
|
-
@reference_model, @reference_field = reference_model(reference)
|
8
7
|
Stripe.api_key = ForestLiana.integrations[:stripe][:api_key]
|
9
8
|
end
|
10
9
|
|
@@ -15,9 +14,9 @@ module ForestLiana
|
|
15
14
|
def perform
|
16
15
|
query = { limit: limit, offset: offset }
|
17
16
|
|
18
|
-
if
|
19
|
-
resource =
|
20
|
-
query[:customer] = resource[
|
17
|
+
if @params[:id] && user_collection && user_field
|
18
|
+
resource = user_collection.find(@params[:id])
|
19
|
+
query[:customer] = resource[user_field]
|
21
20
|
end
|
22
21
|
|
23
22
|
query['include[]'] = 'total_count'
|
@@ -36,9 +35,9 @@ module ForestLiana
|
|
36
35
|
d.amount_due /= 100.00
|
37
36
|
|
38
37
|
query = {}
|
39
|
-
query[
|
40
|
-
if
|
41
|
-
d.customer =
|
38
|
+
query[user_field] = d.customer
|
39
|
+
if user_collection
|
40
|
+
d.customer = user_collection.find_by(query)
|
42
41
|
else
|
43
42
|
d.customer = nil
|
44
43
|
end
|
@@ -48,23 +47,10 @@ module ForestLiana
|
|
48
47
|
end
|
49
48
|
|
50
49
|
def fetch_invoices(params)
|
51
|
-
return if
|
50
|
+
return if @params[:id] && params[:customer].blank?
|
52
51
|
Stripe::Invoice.all(params)
|
53
52
|
end
|
54
53
|
|
55
|
-
def reference_model(reference)
|
56
|
-
resource_name, reference_field = reference.split('.')
|
57
|
-
reference_model = SchemaUtils.find_model_from_table_name(resource_name)
|
58
|
-
|
59
|
-
[reference_model, reference_field]
|
60
|
-
end
|
61
|
-
|
62
|
-
def reference_model_id
|
63
|
-
if @reference_model
|
64
|
-
@params["#{@reference_model.table_name.singularize()}Id"]
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
54
|
def offset
|
69
55
|
return 0 unless pagination?
|
70
56
|
|
@@ -90,6 +76,18 @@ module ForestLiana
|
|
90
76
|
@params[:page] && @params[:page][:number]
|
91
77
|
end
|
92
78
|
|
79
|
+
def user_collection
|
80
|
+
ForestLiana.integrations
|
81
|
+
.try(:[], :stripe)
|
82
|
+
.try(:[], :user_collection)
|
83
|
+
.try(:constantize)
|
84
|
+
end
|
85
|
+
|
86
|
+
def user_field
|
87
|
+
ForestLiana.integrations
|
88
|
+
.try(:[], :stripe)
|
89
|
+
.try(:[], :user_field)
|
90
|
+
end
|
93
91
|
end
|
94
92
|
end
|
95
93
|
|
@@ -4,7 +4,6 @@ module ForestLiana
|
|
4
4
|
|
5
5
|
def initialize(params, secret_key, reference)
|
6
6
|
@params = params
|
7
|
-
@reference_model, @reference_field = reference_model(reference)
|
8
7
|
Stripe.api_key = ForestLiana.integrations[:stripe][:api_key]
|
9
8
|
end
|
10
9
|
|
@@ -15,9 +14,9 @@ module ForestLiana
|
|
15
14
|
def perform
|
16
15
|
query = { limit: limit, offset: offset }
|
17
16
|
|
18
|
-
if
|
19
|
-
resource =
|
20
|
-
query[:customer] = resource[
|
17
|
+
if @params[:id] && user_collection && user_field
|
18
|
+
resource = user_collection.find(@params[:id])
|
19
|
+
query[:customer] = resource[user_field]
|
21
20
|
end
|
22
21
|
|
23
22
|
query['source'] = { object: :card }
|
@@ -34,9 +33,9 @@ module ForestLiana
|
|
34
33
|
d.amount /= 100.00
|
35
34
|
|
36
35
|
query = {}
|
37
|
-
query[
|
38
|
-
if
|
39
|
-
d.customer =
|
36
|
+
query[user_field] = d.customer
|
37
|
+
if user_collection
|
38
|
+
d.customer = user_collection.find_by(query)
|
40
39
|
else
|
41
40
|
d.customer = nil
|
42
41
|
end
|
@@ -46,23 +45,10 @@ module ForestLiana
|
|
46
45
|
end
|
47
46
|
|
48
47
|
def fetch_charges(params)
|
49
|
-
return if
|
48
|
+
return if @params[:id] && params[:customer].blank?
|
50
49
|
Stripe::Charge.all(params)
|
51
50
|
end
|
52
51
|
|
53
|
-
def reference_model(reference)
|
54
|
-
resource_name, reference_field = reference.split('.')
|
55
|
-
reference_model = SchemaUtils.find_model_from_table_name(resource_name)
|
56
|
-
|
57
|
-
[reference_model, reference_field]
|
58
|
-
end
|
59
|
-
|
60
|
-
def reference_model_id
|
61
|
-
if @reference_model
|
62
|
-
@params["#{@reference_model.table_name.singularize()}Id"]
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
52
|
def offset
|
67
53
|
return 0 unless pagination?
|
68
54
|
|
@@ -88,5 +74,17 @@ module ForestLiana
|
|
88
74
|
@params[:page] && @params[:page][:number]
|
89
75
|
end
|
90
76
|
|
77
|
+
def user_collection
|
78
|
+
ForestLiana.integrations
|
79
|
+
.try(:[], :stripe)
|
80
|
+
.try(:[], :user_collection)
|
81
|
+
.try(:constantize)
|
82
|
+
end
|
83
|
+
|
84
|
+
def user_field
|
85
|
+
ForestLiana.integrations
|
86
|
+
.try(:[], :stripe)
|
87
|
+
.try(:[], :user_field)
|
88
|
+
end
|
91
89
|
end
|
92
90
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
Time::DATE_FORMATS[:forest_datetime] = "%d/%m/%Y %H:%M:%S"
|
data/config/routes.rb
CHANGED
@@ -1,9 +1,15 @@
|
|
1
1
|
ForestLiana::Engine.routes.draw do
|
2
2
|
# Stripe Integration
|
3
3
|
get 'stripe_payments' => 'stripe#payments'
|
4
|
+
get ':collection/:id/stripe_payments' => 'stripe#payments'
|
4
5
|
post 'stripe_payments/refunds' => 'stripe#refund'
|
5
|
-
get 'stripe_cards' => 'stripe#cards'
|
6
6
|
get 'stripe_invoices' => 'stripe#invoices'
|
7
|
+
get ':collection/:id/stripe_invoices' => 'stripe#invoices'
|
8
|
+
get ':collection/:id/stripe_cards' => 'stripe#cards'
|
9
|
+
|
10
|
+
# Intercom Integration
|
11
|
+
get ':collection/:id/intercom_conversations' => 'intercom#user_conversations'
|
12
|
+
get ':collection/:id/intercom_attributes' => 'intercom#attributes'
|
7
13
|
|
8
14
|
# Stats
|
9
15
|
post '/stats/:collection' => 'stats#show'
|
@@ -0,0 +1,228 @@
|
|
1
|
+
module ForestLiana
|
2
|
+
class Bootstraper
|
3
|
+
|
4
|
+
def initialize(app)
|
5
|
+
@app = app
|
6
|
+
@logger = Logger.new(STDOUT)
|
7
|
+
end
|
8
|
+
|
9
|
+
def perform
|
10
|
+
create_serializers
|
11
|
+
|
12
|
+
if ForestLiana.jwt_signing_key
|
13
|
+
create_apimap
|
14
|
+
send_apimap
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def create_serializers
|
21
|
+
SchemaUtils.tables_names.map do |table_name|
|
22
|
+
model = SchemaUtils.find_model_from_table_name(table_name)
|
23
|
+
SerializerFactory.new.serializer_for(model) if \
|
24
|
+
model.try(:table_exists?)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Monkey patch the find_serializer_class_name method to specify the
|
28
|
+
# good serializer to use.
|
29
|
+
JSONAPI::Serializer.class_eval do
|
30
|
+
def self.find_serializer_class_name(obj)
|
31
|
+
SerializerFactory.get_serializer_name(obj.class)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def create_apimap
|
37
|
+
SchemaUtils.tables_names.map do |table_name|
|
38
|
+
model = SchemaUtils.find_model_from_table_name(table_name)
|
39
|
+
if model.try(:table_exists?)
|
40
|
+
ForestLiana.apimap << SchemaAdapter.new(model).perform
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
Dir["#{@app.root}/app/models/forest/*.rb"].each {|file| require file }
|
45
|
+
|
46
|
+
setup_stripe_integration if stripe_integration?
|
47
|
+
setup_intercom_integration if intercom_integration?
|
48
|
+
end
|
49
|
+
|
50
|
+
def send_apimap
|
51
|
+
json = JSONAPI::Serializer.serialize(ForestLiana.apimap, {
|
52
|
+
is_collection: true,
|
53
|
+
include: ['actions'],
|
54
|
+
meta: { liana: 'forest-rails', liana_version: liana_version }
|
55
|
+
})
|
56
|
+
|
57
|
+
uri = URI.parse("#{forest_url}/forest/apimaps")
|
58
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
59
|
+
http.use_ssl = true if forest_url.start_with?('https')
|
60
|
+
http.start do |client|
|
61
|
+
request = Net::HTTP::Post.new(uri.path)
|
62
|
+
request.body = json.to_json
|
63
|
+
request['Content-Type'] = 'application/json'
|
64
|
+
request['forest-secret-key'] = ForestLiana.jwt_signing_key
|
65
|
+
response = client.request(request)
|
66
|
+
|
67
|
+
if response.is_a?(Net::HTTPNotFound)
|
68
|
+
@logger.warn "Forest cannot find your project secret key. " \
|
69
|
+
"Please, run `rails g forest_liana:install`."
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def setup_intercom_integration
|
75
|
+
ForestLiana.apimap << ForestLiana::Model::Collection.new({
|
76
|
+
name: 'intercom_conversations',
|
77
|
+
only_for_relationships: true,
|
78
|
+
is_virtual: true,
|
79
|
+
fields: [
|
80
|
+
{ field: :subject, type: 'String' },
|
81
|
+
{ field: :body, type: ['String'], widget: 'link' },
|
82
|
+
{ field: :open, type: 'Boolean'},
|
83
|
+
{ field: :read, type: 'Boolean'},
|
84
|
+
{ field: :assignee, type: 'String' }
|
85
|
+
]
|
86
|
+
})
|
87
|
+
|
88
|
+
ForestLiana.apimap << ForestLiana::Model::Collection.new({
|
89
|
+
name: 'intercom_attributes',
|
90
|
+
only_for_relationships: true,
|
91
|
+
is_virtual: true,
|
92
|
+
fields: [
|
93
|
+
{ field: :created_at, type: 'Date', is_searchable: false },
|
94
|
+
{ field: :updated_at, type: 'Date', is_searchable: false },
|
95
|
+
{ field: :session_count, type: 'Number', is_searchable: false },
|
96
|
+
{ field: :last_seen_ip, type: 'String', is_searchable: false },
|
97
|
+
{ field: :signed_up_at, type: 'Date', is_searchable: false },
|
98
|
+
{ field: :country, type: 'String', is_searchable: false },
|
99
|
+
{ field: :city, type: 'String', is_searchable: false },
|
100
|
+
{ field: :browser, type: 'String', is_searchable: false },
|
101
|
+
{ field: :platform, type: 'String', is_searchable: false },
|
102
|
+
{ field: :companies, type: 'String', is_searchable: false },
|
103
|
+
{ field: :segments, type: 'String', is_searchable: false },
|
104
|
+
{ field: :tags, type: 'String', is_searchable: false },
|
105
|
+
{
|
106
|
+
field: :geoloc,
|
107
|
+
type: 'String',
|
108
|
+
widget: 'google map',
|
109
|
+
is_searchable: false
|
110
|
+
}
|
111
|
+
]
|
112
|
+
})
|
113
|
+
end
|
114
|
+
|
115
|
+
def intercom_integration?
|
116
|
+
ForestLiana.integrations
|
117
|
+
.try(:[], :intercom)
|
118
|
+
.try(:[], :user_collection)
|
119
|
+
.present?
|
120
|
+
end
|
121
|
+
|
122
|
+
def setup_stripe_integration
|
123
|
+
ForestLiana.apimap << ForestLiana::Model::Collection.new({
|
124
|
+
name: 'stripe_payments',
|
125
|
+
is_virtual: true,
|
126
|
+
is_read_only: true,
|
127
|
+
fields: [
|
128
|
+
{ field: :id, type: 'String', is_searchable: false },
|
129
|
+
{ field: :created, type: 'Date', is_searchable: false },
|
130
|
+
{ field: :amount, type: 'Number', is_searchable: false },
|
131
|
+
{ field: :status, type: 'String', is_searchable: false },
|
132
|
+
{ field: :currency, type: 'String', is_searchable: false },
|
133
|
+
{ field: :refunded, type: 'Boolean', is_searchable: false },
|
134
|
+
{ field: :description, type: 'String', is_searchable: false },
|
135
|
+
{
|
136
|
+
field: :customer,
|
137
|
+
type: 'String',
|
138
|
+
reference: 'customers.id',
|
139
|
+
is_searchable: false
|
140
|
+
}
|
141
|
+
],
|
142
|
+
actions: [
|
143
|
+
ForestLiana::Model::Action.new({
|
144
|
+
name: 'Refund',
|
145
|
+
endpoint: '/forest/stripe_payments/refunds'
|
146
|
+
})
|
147
|
+
]
|
148
|
+
})
|
149
|
+
|
150
|
+
ForestLiana.apimap << ForestLiana::Model::Collection.new({
|
151
|
+
name: 'stripe_invoices',
|
152
|
+
is_virtual: true,
|
153
|
+
is_read_only: true,
|
154
|
+
fields: [
|
155
|
+
{ field: :id, type: 'String', is_searchable: false },
|
156
|
+
{ field: :amount_due, type: 'Number', is_searchable: false },
|
157
|
+
{ field: :attempt_count, type: 'Number', is_searchable: false },
|
158
|
+
{ field: :attempted, type: 'Boolean', is_searchable: false },
|
159
|
+
{ field: :closed, type: 'Boolean', is_searchable: false },
|
160
|
+
{ field: :currency, type: 'String', is_searchable: false },
|
161
|
+
{ field: :date, type: 'Date', is_searchable: false },
|
162
|
+
{ field: :forgiven, type: 'Boolean', is_searchable: false },
|
163
|
+
{ field: :period_start, type: 'Date', is_searchable: false },
|
164
|
+
{ field: :period_end, type: 'Date', is_searchable: false },
|
165
|
+
{ field: :subtotal, type: 'Number', is_searchable: false },
|
166
|
+
{ field: :total, type: 'Number', is_searchable: false },
|
167
|
+
{ field: :application_fee, type: 'Number', is_searchable: false },
|
168
|
+
{ field: :tax, type: 'Number', is_searchable: false },
|
169
|
+
{ field: :tax_percent, type: 'Number', is_searchable: false },
|
170
|
+
{
|
171
|
+
field: :customer,
|
172
|
+
type: 'String',
|
173
|
+
reference: 'customers.id',
|
174
|
+
is_searchable: false
|
175
|
+
}
|
176
|
+
]
|
177
|
+
})
|
178
|
+
|
179
|
+
ForestLiana.apimap << ForestLiana::Model::Collection.new({
|
180
|
+
name: 'stripe_cards',
|
181
|
+
is_virtual: true,
|
182
|
+
is_read_only: true,
|
183
|
+
only_for_relationships: true,
|
184
|
+
fields: [
|
185
|
+
{ field: :id, type: 'String', is_searchable: false },
|
186
|
+
{ field: :last4, type: 'String', is_searchable: false },
|
187
|
+
{ field: :brand, type: 'String', is_searchable: false },
|
188
|
+
{ field: :funding, type: 'String', is_searchable: false },
|
189
|
+
{ field: :exp_month, type: 'Number', is_searchable: false },
|
190
|
+
{ field: :exp_year, type: 'Number', is_searchable: false },
|
191
|
+
{ field: :country, type: 'String', is_searchable: false },
|
192
|
+
{ field: :name, type: 'String', is_searchable: false },
|
193
|
+
{ field: :address_line1, type: 'String', is_searchable: false },
|
194
|
+
{ field: :address_line2, type: 'String', is_searchable: false },
|
195
|
+
{ field: :address_city, type: 'String', is_searchable: false },
|
196
|
+
{ field: :address_state, type: 'String', is_searchable: false },
|
197
|
+
{ field: :address_zip, type: 'String', is_searchable: false },
|
198
|
+
{ field: :address_country, type: 'String', is_searchable: false },
|
199
|
+
{ field: :cvc_check, type: 'String', is_searchable: false },
|
200
|
+
{
|
201
|
+
field: :customer,
|
202
|
+
type: 'String',
|
203
|
+
reference: 'customers.id',
|
204
|
+
is_searchable: false
|
205
|
+
}
|
206
|
+
]
|
207
|
+
})
|
208
|
+
end
|
209
|
+
|
210
|
+
def stripe_integration?
|
211
|
+
ForestLiana.integrations
|
212
|
+
.try(:[], :stripe)
|
213
|
+
.try(:[], :api_key)
|
214
|
+
.present?
|
215
|
+
end
|
216
|
+
|
217
|
+
def forest_url
|
218
|
+
ENV['FOREST_URL'] || 'https://forestadmin-server.herokuapp.com';
|
219
|
+
end
|
220
|
+
|
221
|
+
def liana_version
|
222
|
+
Gem::Specification.find_all_by_name('forest_liana')
|
223
|
+
.try(:first)
|
224
|
+
.try(:version)
|
225
|
+
.try(:to_s)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
data/lib/forest_liana/engine.rb
CHANGED
@@ -2,12 +2,14 @@ require 'rack/cors'
|
|
2
2
|
require 'stripe'
|
3
3
|
require 'jsonapi-serializers'
|
4
4
|
require 'groupdate'
|
5
|
-
require
|
5
|
+
require 'net/http'
|
6
|
+
require 'intercom'
|
7
|
+
require 'useragent'
|
8
|
+
require_relative 'bootstraper'
|
6
9
|
|
7
10
|
module ForestLiana
|
8
11
|
class Engine < ::Rails::Engine
|
9
12
|
isolate_namespace ForestLiana
|
10
|
-
logger = Logger.new(STDOUT)
|
11
13
|
|
12
14
|
config.middleware.insert_before 0, 'Rack::Cors' do
|
13
15
|
allow do
|
@@ -18,59 +20,8 @@ module ForestLiana
|
|
18
20
|
end
|
19
21
|
|
20
22
|
config.after_initialize do |app|
|
21
|
-
|
22
|
-
|
23
|
-
model = SchemaUtils.find_model_from_table_name(table_name)
|
24
|
-
SerializerFactory.new.serializer_for(model) if \
|
25
|
-
model.try(:table_exists?)
|
26
|
-
end
|
27
|
-
|
28
|
-
# Monkey patch the find_serializer_class_name method to specify the
|
29
|
-
# good serializer to use.
|
30
|
-
JSONAPI::Serializer.class_eval do
|
31
|
-
def self.find_serializer_class_name(obj)
|
32
|
-
SerializerFactory.get_serializer_name(obj.class)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
if ForestLiana.jwt_signing_key
|
37
|
-
forest_url = ENV['FOREST_URL'] ||
|
38
|
-
'https://forestadmin-server.herokuapp.com';
|
39
|
-
|
40
|
-
SchemaUtils.tables_names.map do |table_name|
|
41
|
-
model = SchemaUtils.find_model_from_table_name(table_name)
|
42
|
-
if model.try(:table_exists?)
|
43
|
-
ForestLiana.apimap << SchemaAdapter.new(model).perform
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
Dir["#{app.root}/app/models/forest/*.rb"].each {|file| require file }
|
48
|
-
|
49
|
-
liana_version = Gem::Specification.find_by_name('forest_liana')
|
50
|
-
.version.to_s
|
51
|
-
json = JSONAPI::Serializer.serialize(ForestLiana.apimap, {
|
52
|
-
is_collection: true,
|
53
|
-
include: ['actions'],
|
54
|
-
meta: { liana: 'forest-rails', liana_version: liana_version }
|
55
|
-
})
|
56
|
-
|
57
|
-
uri = URI.parse("#{forest_url}/forest/apimaps")
|
58
|
-
http = Net::HTTP.new(uri.host, uri.port)
|
59
|
-
http.use_ssl = true if forest_url.start_with?('https')
|
60
|
-
http.start do |client|
|
61
|
-
request = Net::HTTP::Post.new(uri.path)
|
62
|
-
request.body = json.to_json
|
63
|
-
request['Content-Type'] = 'application/json'
|
64
|
-
request['forest-secret-key'] = ForestLiana.jwt_signing_key
|
65
|
-
response = client.request(request)
|
66
|
-
|
67
|
-
if response.is_a?(Net::HTTPNotFound)
|
68
|
-
logger.warn "Forest cannot find your project secret key. " \
|
69
|
-
"Please, run `rails g forest_liana:install`."
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
23
|
+
return if Rails.env.test?
|
24
|
+
Bootstraper.new(app).perform
|
74
25
|
end
|
75
26
|
end
|
76
27
|
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: 1.1.
|
4
|
+
version: 1.1.23
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sandro Munda
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-01-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -108,6 +108,34 @@ dependencies:
|
|
108
108
|
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: intercom
|
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'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: useragent
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
111
139
|
description: Forest Rails Liana
|
112
140
|
email:
|
113
141
|
- sandro@munda.me
|
@@ -124,6 +152,7 @@ files:
|
|
124
152
|
- app/controllers/forest_liana/apimaps_controller.rb
|
125
153
|
- app/controllers/forest_liana/application_controller.rb
|
126
154
|
- app/controllers/forest_liana/associations_controller.rb
|
155
|
+
- app/controllers/forest_liana/intercom_controller.rb
|
127
156
|
- app/controllers/forest_liana/resources_controller.rb
|
128
157
|
- app/controllers/forest_liana/stats_controller.rb
|
129
158
|
- app/controllers/forest_liana/stripe_controller.rb
|
@@ -134,6 +163,8 @@ files:
|
|
134
163
|
- app/models/forest_liana/model/stat.rb
|
135
164
|
- app/serializers/forest_liana/action_serializer.rb
|
136
165
|
- app/serializers/forest_liana/collection_serializer.rb
|
166
|
+
- app/serializers/forest_liana/intercom_attribute_serializer.rb
|
167
|
+
- app/serializers/forest_liana/intercom_conversation_serializer.rb
|
137
168
|
- app/serializers/forest_liana/serializer_factory.rb
|
138
169
|
- app/serializers/forest_liana/stat_serializer.rb
|
139
170
|
- app/serializers/forest_liana/stripe_card_serializer.rb
|
@@ -141,6 +172,8 @@ files:
|
|
141
172
|
- app/serializers/forest_liana/stripe_payment_serializer.rb
|
142
173
|
- app/services/forest_liana/collection.rb
|
143
174
|
- app/services/forest_liana/has_many_getter.rb
|
175
|
+
- app/services/forest_liana/intercom_attributes_getter.rb
|
176
|
+
- app/services/forest_liana/intercom_conversations_getter.rb
|
144
177
|
- app/services/forest_liana/line_stat_getter.rb
|
145
178
|
- app/services/forest_liana/operator_value_parser.rb
|
146
179
|
- app/services/forest_liana/pie_stat_getter.rb
|
@@ -158,8 +191,10 @@ files:
|
|
158
191
|
- app/views/layouts/forest_liana/application.html.erb
|
159
192
|
- config/initializers/arel-helpers.rb
|
160
193
|
- config/initializers/mimetype.rb
|
194
|
+
- config/initializers/time_formats.rb
|
161
195
|
- config/routes.rb
|
162
196
|
- lib/forest_liana.rb
|
197
|
+
- lib/forest_liana/bootstraper.rb
|
163
198
|
- lib/forest_liana/engine.rb
|
164
199
|
- lib/forest_liana/version.rb
|
165
200
|
- lib/generators/forest_liana/install_generator.rb
|