forest_liana 1.4.4 → 1.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/controllers/forest_liana/sessions_controller.rb +28 -15
- data/app/deserializers/forest_liana/resource_deserializer.rb +10 -2
- data/app/serializers/forest_liana/serializer_factory.rb +34 -21
- data/app/services/forest_liana/allowed_users_getter.rb +25 -13
- data/app/services/forest_liana/has_many_getter.rb +0 -10
- data/app/services/forest_liana/pie_stat_getter.rb +14 -4
- data/app/services/forest_liana/resources_getter.rb +1 -10
- data/app/services/forest_liana/schema_adapter.rb +17 -12
- data/config/initializers/logger.rb +25 -0
- data/config/routes.rb +20 -18
- data/lib/forest_liana.rb +2 -3
- data/lib/forest_liana/bootstraper.rb +53 -60
- data/lib/forest_liana/collection.rb +6 -3
- data/lib/forest_liana/engine.rb +23 -11
- data/lib/forest_liana/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3abc2cedf799ed432538f68b9710ed9f48a20b69
|
4
|
+
data.tar.gz: 6e7adcf88252854a67c0c6d3d44f50b510435d17
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8435daf472d626aacca2c6b7cdafb213fe8018993a15b306e21ec84d0a40211f90cae59dcdf87b78d5efc16885d9899c78c22dfacdae16e47ae9aea99482b30c
|
7
|
+
data.tar.gz: af9bf03170b9c886a26bb193057710ac7af2f981d56dec2f6766a56d26d050e9890a41334257b035ea888bbdec8c0eb95ecf957826be4be8760e858580d56363
|
@@ -2,34 +2,35 @@ module ForestLiana
|
|
2
2
|
class SessionsController < ActionController::Base
|
3
3
|
|
4
4
|
def create
|
5
|
-
|
5
|
+
@user_class = ForestLiana.user_class_name.constantize rescue nil
|
6
|
+
|
6
7
|
user = check_user
|
7
8
|
token = encode_token(user) if user
|
8
9
|
|
9
10
|
if token
|
10
11
|
render json: { token: token }, serializer: nil
|
11
12
|
else
|
12
|
-
|
13
|
+
if !has_internal_authentication? && ForestLiana.allowed_users.empty?
|
14
|
+
render serializer: nil, json: JSONAPI::Serializer.serialize_errors(
|
15
|
+
[{ detail: 'Forest cannot retrieve any users for the project ' \
|
16
|
+
'you\'re trying to unlock.' }]), status: :unauthorized
|
17
|
+
else
|
18
|
+
head :unauthorized
|
19
|
+
end
|
13
20
|
end
|
14
21
|
end
|
15
22
|
|
16
23
|
private
|
17
24
|
|
18
|
-
def fetch_allowed_users
|
19
|
-
AllowedUsersGetter.new.perform(params['renderingId'])
|
20
|
-
end
|
21
|
-
|
22
25
|
def check_user
|
23
|
-
|
24
|
-
|
25
|
-
user =
|
26
|
-
|
27
|
-
|
28
|
-
if BCrypt::Password.new(user['password_hash']) == params['password']
|
29
|
-
user
|
30
|
-
end
|
31
|
-
# NOTICE: Query Forest server for authentication.
|
26
|
+
if has_internal_authentication?
|
27
|
+
# NOTICE: Use the ForestUser table for authentication.
|
28
|
+
user = user_class.find_by(email: params['email'])
|
29
|
+
user if !user.blank? && authenticate_internal_user(user['password_digest'])
|
32
30
|
else
|
31
|
+
# NOTICE: Query Forest server for authentication.
|
32
|
+
fetch_allowed_users
|
33
|
+
|
33
34
|
ForestLiana.allowed_users.find do |allowed_user|
|
34
35
|
allowed_user['email'] == params['email'] &&
|
35
36
|
BCrypt::Password.new(allowed_user['password']) == params['password']
|
@@ -37,6 +38,18 @@ module ForestLiana
|
|
37
38
|
end
|
38
39
|
end
|
39
40
|
|
41
|
+
def fetch_allowed_users
|
42
|
+
AllowedUsersGetter.new.perform(params['renderingId'])
|
43
|
+
end
|
44
|
+
|
45
|
+
def has_internal_authentication?
|
46
|
+
@user_class && defined? @user_class
|
47
|
+
end
|
48
|
+
|
49
|
+
def authenticate_internal_user(password_digest)
|
50
|
+
BCrypt::Password.new(password_digest).is_password?(params['password'])
|
51
|
+
end
|
52
|
+
|
40
53
|
def encode_token(user)
|
41
54
|
JWT.encode({
|
42
55
|
exp: Time.now.to_i + 2.weeks.to_i,
|
@@ -11,6 +11,7 @@ module ForestLiana
|
|
11
11
|
|
12
12
|
def perform
|
13
13
|
@attributes = extract_attributes
|
14
|
+
extract_attributes_serialize
|
14
15
|
extract_relationships if @with_relationships
|
15
16
|
extract_paperclip
|
16
17
|
extract_carrierwave
|
@@ -22,12 +23,19 @@ module ForestLiana
|
|
22
23
|
|
23
24
|
def extract_attributes
|
24
25
|
if @params[:data][:attributes]
|
25
|
-
@params['data']['attributes'].select {|
|
26
|
+
@params['data']['attributes'].select { |attribute| column?(attribute) }
|
26
27
|
else
|
27
28
|
ActionController::Parameters.new()
|
28
29
|
end
|
29
30
|
end
|
30
31
|
|
32
|
+
def extract_attributes_serialize
|
33
|
+
@resource.serialized_attributes.each do |attribute, serializer|
|
34
|
+
value = @params[:data][:attributes][attribute]
|
35
|
+
@attributes[attribute] = JSON::parse(value)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
31
39
|
def extract_relationships
|
32
40
|
if @params['data']['relationships']
|
33
41
|
@params['data']['relationships'].each do |name, relationship|
|
@@ -112,7 +120,7 @@ module ForestLiana
|
|
112
120
|
end
|
113
121
|
|
114
122
|
def column?(attribute)
|
115
|
-
@resource.columns.find {|
|
123
|
+
@resource.columns.find { |column| column.name == attribute }.present?
|
116
124
|
end
|
117
125
|
|
118
126
|
def carrierwave_attribute?(attr)
|
@@ -150,14 +150,14 @@ module ForestLiana
|
|
150
150
|
end
|
151
151
|
}
|
152
152
|
|
153
|
-
attributes(active_record_class).each do |
|
154
|
-
serializer.attribute(
|
153
|
+
attributes(active_record_class).each do |attribute|
|
154
|
+
serializer.attribute(attribute)
|
155
155
|
end
|
156
156
|
|
157
|
-
# NOTICE: Format
|
158
|
-
attributes_time(active_record_class).each do |
|
159
|
-
serializer.attribute(
|
160
|
-
value = object.send(
|
157
|
+
# NOTICE: Format time type fields during the serialization.
|
158
|
+
attributes_time(active_record_class).each do |attribute|
|
159
|
+
serializer.attribute(attribute) do |x|
|
160
|
+
value = object.send(attribute)
|
161
161
|
if value
|
162
162
|
match = /(\d{2}:\d{2}:\d{2})/.match(value.to_s)
|
163
163
|
(match && match[1]) ? match[1] : nil
|
@@ -167,21 +167,29 @@ module ForestLiana
|
|
167
167
|
end
|
168
168
|
end
|
169
169
|
|
170
|
-
#
|
170
|
+
# NOTICE: Format serialized fields.
|
171
|
+
active_record_class.serialized_attributes.each do |attribute, serialization|
|
172
|
+
serializer.attribute(attribute) do |x|
|
173
|
+
value = object.send(attribute)
|
174
|
+
value ? value.to_json : nil
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
# NOTICE: Format CarrierWave url attribute
|
171
179
|
if active_record_class.respond_to?(:mount_uploader)
|
172
180
|
active_record_class.uploaders.each do |key, value|
|
173
181
|
serializer.attribute(key) { |x| object.send(key).try(:url) }
|
174
182
|
end
|
175
183
|
end
|
176
184
|
|
177
|
-
# Paperclip url attribute
|
185
|
+
# NOTICE: Format Paperclip url attribute
|
178
186
|
if active_record_class.respond_to?(:attachment_definitions)
|
179
187
|
active_record_class.attachment_definitions.each do |key, value|
|
180
188
|
serializer.attribute(key) { |x| object.send(key) }
|
181
189
|
end
|
182
190
|
end
|
183
191
|
|
184
|
-
# ActsAsTaggable attribute
|
192
|
+
# NOTICE: Format ActsAsTaggable attribute
|
185
193
|
if active_record_class.respond_to?(:acts_as_taggable) &&
|
186
194
|
active_record_class.acts_as_taggable.respond_to?(:to_a)
|
187
195
|
active_record_class.acts_as_taggable.to_a.each do |key, value|
|
@@ -191,7 +199,7 @@ module ForestLiana
|
|
191
199
|
end
|
192
200
|
end
|
193
201
|
|
194
|
-
# Devise attributes
|
202
|
+
# NOTICE: Format Devise attributes
|
195
203
|
if active_record_class.respond_to?(:devise_modules?)
|
196
204
|
serializer.attribute('password') do |x|
|
197
205
|
'**********'
|
@@ -199,18 +207,23 @@ module ForestLiana
|
|
199
207
|
end
|
200
208
|
|
201
209
|
SchemaUtils.associations(active_record_class).each do |a|
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
210
|
+
begin
|
211
|
+
if SchemaUtils.model_included?(a.klass)
|
212
|
+
serializer.send(serializer_association(a), a.name) {
|
213
|
+
if [:has_one, :belongs_to].include?(a.macro)
|
214
|
+
begin
|
215
|
+
object.send(a.name)
|
216
|
+
rescue ActiveRecord::RecordNotFound
|
217
|
+
nil
|
218
|
+
end
|
219
|
+
else
|
220
|
+
[]
|
209
221
|
end
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
222
|
+
}
|
223
|
+
end
|
224
|
+
rescue NameError
|
225
|
+
# NOTICE: Let this error silent, a bad association warning will be
|
226
|
+
# displayed in the schema adapter.
|
214
227
|
end
|
215
228
|
end
|
216
229
|
|
@@ -4,23 +4,35 @@ module ForestLiana
|
|
4
4
|
uri = URI.parse("#{forest_url}/forest/renderings/#{renderingId}/allowed-users")
|
5
5
|
http = Net::HTTP.new(uri.host, uri.port)
|
6
6
|
http.use_ssl = true if forest_url.start_with?('https')
|
7
|
-
http.start do |client|
|
8
|
-
request = Net::HTTP::Get.new(uri.path)
|
9
|
-
request['Content-Type'] = 'application/json'
|
10
|
-
request['forest-secret-key'] = ForestLiana.secret_key
|
11
|
-
response = client.request(request)
|
12
7
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
8
|
+
begin
|
9
|
+
http.start do |client|
|
10
|
+
request = Net::HTTP::Get.new(uri.path)
|
11
|
+
request['Content-Type'] = 'application/json'
|
12
|
+
request['forest-secret-key'] = ForestLiana.secret_key
|
13
|
+
response = client.request(request)
|
18
14
|
|
19
|
-
|
15
|
+
if response.is_a?(Net::HTTPOK)
|
16
|
+
body = JSON.parse(response.body)
|
17
|
+
ForestLiana.allowed_users = body['data'].map do |d|
|
18
|
+
user = d['attributes']
|
19
|
+
user['id'] = d['id']
|
20
|
+
|
21
|
+
user
|
22
|
+
end
|
23
|
+
elsif response.is_a?(Net::HTTPNotFound)
|
24
|
+
FOREST_LOGGER.error "Cannot retrieve the project you\'re trying " \
|
25
|
+
"to unlock. Can you check that you properly copied the Forest " \
|
26
|
+
"secret key in the forest_liana initializer?"
|
27
|
+
else
|
28
|
+
FOREST_LOGGER.error "Cannot retrieve any users for the project " \
|
29
|
+
"you\'re trying to unlock. An error occured in Forest API."
|
30
|
+
[]
|
20
31
|
end
|
21
|
-
else
|
22
|
-
[]
|
23
32
|
end
|
33
|
+
rescue => exception
|
34
|
+
FOREST_LOGGER.error "Cannot retrieve any users for the project " \
|
35
|
+
"you\'re trying to unlock. Forest API seems to be down right now."
|
24
36
|
end
|
25
37
|
end
|
26
38
|
|
@@ -18,7 +18,6 @@ module ForestLiana
|
|
18
18
|
.unscoped
|
19
19
|
.find(@params[:id])
|
20
20
|
.send(@params[:association_name])
|
21
|
-
.select(select)
|
22
21
|
.eager_load(includes)
|
23
22
|
@records = sort_query
|
24
23
|
end
|
@@ -50,15 +49,6 @@ module ForestLiana
|
|
50
49
|
|
51
50
|
private
|
52
51
|
|
53
|
-
def select
|
54
|
-
column_names = @association.klass.column_names.map { |name| name.to_sym }
|
55
|
-
if @field_names_requested
|
56
|
-
column_names & @field_names_requested
|
57
|
-
else
|
58
|
-
column_names
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
52
|
def association_table_name
|
63
53
|
@resource.reflect_on_association(@params[:association_name])
|
64
54
|
.try(:table_name)
|
@@ -22,23 +22,33 @@ module ForestLiana
|
|
22
22
|
.unscoped
|
23
23
|
.eager_load(includes)
|
24
24
|
.where(conditions.join(filter_operator))
|
25
|
-
.group(
|
25
|
+
.group(group_by_field)
|
26
26
|
.order(order)
|
27
27
|
.send(@params[:aggregate].downcase, @params[:aggregate_field])
|
28
|
-
.map do |
|
28
|
+
.map do |key, value|
|
29
29
|
# NOTICE: Display the enum name instead of a integer if "enum" type
|
30
30
|
if @resource.respond_to?(:defined_enums) &&
|
31
31
|
@resource.defined_enums.has_key?(@params[:group_by_field])
|
32
|
-
|
32
|
+
key = @resource.defined_enums[@params[:group_by_field]].invert[key]
|
33
33
|
end
|
34
34
|
|
35
|
-
{ key:
|
35
|
+
{ key: key, value: value }
|
36
36
|
end
|
37
37
|
|
38
38
|
@record = Model::Stat.new(value: value)
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
|
+
def group_by_field
|
43
|
+
if @params[:group_by_field].include? ':'
|
44
|
+
association, field = @params[:group_by_field].split ':'
|
45
|
+
resource = @resource.reflect_on_association(association.to_sym)
|
46
|
+
"#{resource.table_name}.#{field}"
|
47
|
+
else
|
48
|
+
"#{@resource.table_name}.#{@params[:group_by_field]}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
42
52
|
def order
|
43
53
|
# NOTICE: The generated alias for a count is "count_all", for a sum the
|
44
54
|
# alias looks like "sum_#{aggregate_field}"
|
@@ -36,7 +36,7 @@ module ForestLiana
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def records
|
39
|
-
@sorted_records.
|
39
|
+
@sorted_records.offset(offset).limit(limit).to_a
|
40
40
|
end
|
41
41
|
|
42
42
|
def count
|
@@ -109,15 +109,6 @@ module ForestLiana
|
|
109
109
|
@resource.reflect_on_association(field.to_sym).present?
|
110
110
|
end
|
111
111
|
|
112
|
-
def select
|
113
|
-
column_names = @resource.column_names.map { |name| name.to_sym }
|
114
|
-
if @field_names_requested
|
115
|
-
column_names & @field_names_requested
|
116
|
-
else
|
117
|
-
column_names
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
112
|
def offset
|
122
113
|
return 0 unless pagination?
|
123
114
|
|
@@ -8,10 +8,11 @@ module ForestLiana
|
|
8
8
|
add_columns
|
9
9
|
add_associations
|
10
10
|
|
11
|
-
# ActsAsTaggable
|
12
|
-
if @model.respond_to?(:acts_as_taggable) &&
|
11
|
+
# NOTICE: Add ActsAsTaggable fields
|
12
|
+
if @model.respond_to?(:acts_as_taggable) &&
|
13
|
+
@model.acts_as_taggable.respond_to?(:to_a) &&
|
13
14
|
@model.acts_as_taggable.to_a.each do |key, value|
|
14
|
-
field = collection.fields.find {|x| x[:field] == key.to_s}
|
15
|
+
field = collection.fields.find { |x| x[:field] == key.to_s }
|
15
16
|
|
16
17
|
if field
|
17
18
|
field[:type] = 'String'
|
@@ -25,7 +26,7 @@ module ForestLiana
|
|
25
26
|
end
|
26
27
|
end
|
27
28
|
|
28
|
-
# Devise
|
29
|
+
# NOTICE: Add Devise fields
|
29
30
|
if @model.respond_to?(:devise_modules?)
|
30
31
|
collection.fields << {
|
31
32
|
field: 'password',
|
@@ -66,7 +67,7 @@ module ForestLiana
|
|
66
67
|
collection.fields << get_schema_for_column(column)
|
67
68
|
end
|
68
69
|
|
69
|
-
# Intercom
|
70
|
+
# NOTICE: Add Intercom fields
|
70
71
|
if ForestLiana.integrations.try(:[], :intercom)
|
71
72
|
.try(:[], :mapping).try(:include?, @model.name)
|
72
73
|
|
@@ -91,7 +92,7 @@ module ForestLiana
|
|
91
92
|
}
|
92
93
|
end
|
93
94
|
|
94
|
-
# Stripe
|
95
|
+
# NOTICE: Add Stripe fields
|
95
96
|
stripe_mapping = ForestLiana.integrations.try(:[], :stripe)
|
96
97
|
.try(:[], :mapping)
|
97
98
|
|
@@ -149,7 +150,7 @@ module ForestLiana
|
|
149
150
|
end
|
150
151
|
end
|
151
152
|
|
152
|
-
# Paperclip url
|
153
|
+
# NOTICE: Add Paperclip url attributes
|
153
154
|
if @model.respond_to?(:attachment_definitions)
|
154
155
|
@model.attachment_definitions.each do |key, value|
|
155
156
|
collection.fields << { field: key, type: 'File' }
|
@@ -161,10 +162,10 @@ module ForestLiana
|
|
161
162
|
end
|
162
163
|
end
|
163
164
|
|
164
|
-
# CarrierWave
|
165
|
+
# NOTICE: Add CarrierWave attributes
|
165
166
|
if @model.respond_to?(:uploaders)
|
166
167
|
@model.uploaders.each do |key, value|
|
167
|
-
field = collection.fields.find {|x| x[:field] == key.to_s}
|
168
|
+
field = collection.fields.find { |x| x[:field] == key.to_s }
|
168
169
|
field[:type] = 'File' if field
|
169
170
|
end
|
170
171
|
end
|
@@ -173,7 +174,7 @@ module ForestLiana
|
|
173
174
|
def add_associations
|
174
175
|
SchemaUtils.associations(@model).each do |association|
|
175
176
|
begin
|
176
|
-
# NOTICE:
|
177
|
+
# NOTICE: Delete the association if the targeted model is excluded.
|
177
178
|
if !SchemaUtils.model_included?(association.klass)
|
178
179
|
field = collection.fields.find do |x|
|
179
180
|
x[:field] == association.foreign_key
|
@@ -189,8 +190,12 @@ module ForestLiana
|
|
189
190
|
else
|
190
191
|
collection.fields << get_schema_for_association(association)
|
191
192
|
end
|
192
|
-
rescue
|
193
|
-
|
193
|
+
rescue NameError
|
194
|
+
FOREST_LOGGER.warn "The association \"#{association.name.to_s}\" " \
|
195
|
+
"does not seem to exist for model \"#{@model.name}\"."
|
196
|
+
rescue => exception
|
197
|
+
FOREST_LOGGER.error "An error occured trying to add " \
|
198
|
+
"\"#{association.name.to_s}\" association:\n#{exception}"
|
194
199
|
end
|
195
200
|
end
|
196
201
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
module ForestLiana
|
3
|
+
class Logger
|
4
|
+
class << self
|
5
|
+
def log
|
6
|
+
logger = ::Logger.new(STDOUT)
|
7
|
+
logger_colors = {
|
8
|
+
DEBUG: 34,
|
9
|
+
WARN: 33,
|
10
|
+
ERROR: 31,
|
11
|
+
INFO: 37
|
12
|
+
}
|
13
|
+
|
14
|
+
logger.formatter = proc do |severity, datetime, progname, message|
|
15
|
+
displayed_message = "[#{datetime.to_s(:db)}] Forest 🌳🌳🌳 #{message}\n"
|
16
|
+
"\e[#{logger_colors[severity.to_sym]}m#{displayed_message}\033[0m"
|
17
|
+
end
|
18
|
+
|
19
|
+
logger
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
FOREST_LOGGER = ForestLiana::Logger.log
|
data/config/routes.rb
CHANGED
@@ -1,7 +1,26 @@
|
|
1
1
|
ForestLiana::Engine.routes.draw do
|
2
|
-
#
|
2
|
+
# Onboarding
|
3
|
+
get '/' => 'apimaps#index'
|
4
|
+
|
5
|
+
# Session
|
3
6
|
post 'sessions' => 'sessions#create'
|
4
7
|
|
8
|
+
# CRUD
|
9
|
+
get ':collection' => 'resources#index'
|
10
|
+
get ':collection/:id' => 'resources#show'
|
11
|
+
post ':collection' => 'resources#create'
|
12
|
+
put ':collection/:id' => 'resources#update'
|
13
|
+
delete ':collection/:id' => 'resources#destroy'
|
14
|
+
|
15
|
+
# Associations
|
16
|
+
get ':collection/:id/relationships/:association_name' => 'associations#index'
|
17
|
+
put ':collection/:id/relationships/:association_name' => 'associations#update'
|
18
|
+
post ':collection/:id/relationships/:association_name' => 'associations#associate'
|
19
|
+
delete ':collection/:id/relationships/:association_name' => 'associations#dissociate'
|
20
|
+
|
21
|
+
# Stats
|
22
|
+
post '/stats/:collection' => 'stats#show'
|
23
|
+
|
5
24
|
# Stripe Integration
|
6
25
|
get '(:collection)_stripe_payments' => 'stripe#payments'
|
7
26
|
get ':collection/:id/stripe_payments' => 'stripe#payments'
|
@@ -16,21 +35,4 @@ ForestLiana::Engine.routes.draw do
|
|
16
35
|
# Intercom Integration
|
17
36
|
get ':collection/:id/intercom_conversations' => 'intercom#user_conversations'
|
18
37
|
get ':collection/:id/intercom_attributes' => 'intercom#attributes'
|
19
|
-
|
20
|
-
# Stats
|
21
|
-
post '/stats/:collection' => 'stats#show'
|
22
|
-
|
23
|
-
# CRUD
|
24
|
-
get '/' => 'apimaps#index'
|
25
|
-
get ':collection' => 'resources#index'
|
26
|
-
get ':collection/:id' => 'resources#show'
|
27
|
-
post ':collection' => 'resources#create'
|
28
|
-
put ':collection/:id' => 'resources#update'
|
29
|
-
delete ':collection/:id' => 'resources#destroy'
|
30
|
-
|
31
|
-
# Associations
|
32
|
-
get ':collection/:id/relationships/:association_name' => 'associations#index'
|
33
|
-
put ':collection/:id/relationships/:association_name' => 'associations#update'
|
34
|
-
post ':collection/:id/relationships/:association_name' => 'associations#associate'
|
35
|
-
delete ':collection/:id/relationships/:association_name' => 'associations#dissociate'
|
36
38
|
end
|
data/lib/forest_liana.rb
CHANGED
@@ -15,13 +15,12 @@ module ForestLiana
|
|
15
15
|
mattr_accessor :models
|
16
16
|
mattr_accessor :excluded_models
|
17
17
|
mattr_accessor :included_models
|
18
|
-
|
19
|
-
# Legacy.
|
20
|
-
mattr_accessor :jwt_signing_key
|
18
|
+
mattr_accessor :user_class_name
|
21
19
|
|
22
20
|
self.apimap = []
|
23
21
|
self.allowed_users = []
|
24
22
|
self.models = []
|
25
23
|
self.excluded_models = []
|
26
24
|
self.included_models = []
|
25
|
+
self.user_class_name = nil
|
27
26
|
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
# encoding: UTF-8
|
2
1
|
module ForestLiana
|
3
2
|
class Bootstraper
|
4
3
|
|
@@ -7,29 +6,6 @@ module ForestLiana
|
|
7
6
|
|
8
7
|
@integration_stripe_valid = false
|
9
8
|
@integration_intercom_valid = false
|
10
|
-
|
11
|
-
@logger = Logger.new(STDOUT)
|
12
|
-
|
13
|
-
@@logger_colors = {
|
14
|
-
DEBUG: 34,
|
15
|
-
WARN: 33,
|
16
|
-
ERROR: 31,
|
17
|
-
INFO: 37
|
18
|
-
}
|
19
|
-
|
20
|
-
@logger.formatter = proc do |severity, datetime, progname, message|
|
21
|
-
displayed_message = "[#{datetime.to_s(:db)}] Forest 🌳🌳🌳 #{message}\n"
|
22
|
-
"\e[#{@@logger_colors[severity.to_sym]}m#{displayed_message}\033[0m"
|
23
|
-
end
|
24
|
-
|
25
|
-
if ForestLiana.jwt_signing_key
|
26
|
-
@logger.warn "DEPRECATION WARNING: the use of \
|
27
|
-
ForestLiana.jwt_signing_key (config/initializers/forest_liana.rb) is \
|
28
|
-
deprecated. Use ForestLiana.secret_key and ForestLiana.auth_key instead. \
|
29
|
-
More info at: https://github.com/ForestAdmin/forest-rails/releases/tag/1.2.0"
|
30
|
-
ForestLiana.secret_key = ForestLiana.jwt_signing_key
|
31
|
-
ForestLiana.auth_key = ForestLiana.jwt_signing_key
|
32
|
-
end
|
33
9
|
end
|
34
10
|
|
35
11
|
def perform
|
@@ -47,7 +23,7 @@ More info at: https://github.com/ForestAdmin/forest-rails/releases/tag/1.2.0"
|
|
47
23
|
private
|
48
24
|
|
49
25
|
def fetch_sti_models(model)
|
50
|
-
type_field = model.columns.find {|c| c.name == 'type' }
|
26
|
+
type_field = model.columns.find { |c| c.name == 'type' }
|
51
27
|
if type_field
|
52
28
|
model.descendants.each do |sti_model|
|
53
29
|
if analyze_model?(sti_model)
|
@@ -63,19 +39,23 @@ More info at: https://github.com/ForestAdmin/forest-rails/releases/tag/1.2.0"
|
|
63
39
|
end
|
64
40
|
|
65
41
|
def fetch_models
|
66
|
-
ActiveRecord::Base.subclasses.each {|model| fetch_model(model)}
|
42
|
+
ActiveRecord::Base.subclasses.each { |model| fetch_model(model) }
|
67
43
|
end
|
68
44
|
|
69
45
|
def fetch_model(model)
|
70
|
-
|
71
|
-
model.
|
72
|
-
|
73
|
-
|
46
|
+
begin
|
47
|
+
if model.abstract_class?
|
48
|
+
model.descendants.each { |submodel| fetch_model(submodel) }
|
49
|
+
else
|
50
|
+
fetch_sti_models(model) if model.try(:table_exists?)
|
74
51
|
|
75
|
-
|
76
|
-
|
52
|
+
if analyze_model?(model)
|
53
|
+
ForestLiana.models << model
|
54
|
+
end
|
77
55
|
end
|
78
|
-
|
56
|
+
rescue => exception
|
57
|
+
FOREST_LOGGER.error "Cannot fetch properly model #{model.name}:\n" \
|
58
|
+
"#{exception}"
|
79
59
|
end
|
80
60
|
end
|
81
61
|
|
@@ -111,7 +91,7 @@ More info at: https://github.com/ForestAdmin/forest-rails/releases/tag/1.2.0"
|
|
111
91
|
cast_to_array(ForestLiana.integrations[:stripe][:mapping])
|
112
92
|
@integration_stripe_valid = true
|
113
93
|
else
|
114
|
-
|
94
|
+
FOREST_LOGGER.error 'Cannot setup properly your Stripe integration.'
|
115
95
|
end
|
116
96
|
end
|
117
97
|
|
@@ -121,7 +101,7 @@ More info at: https://github.com/ForestAdmin/forest-rails/releases/tag/1.2.0"
|
|
121
101
|
cast_to_array(ForestLiana.integrations[:intercom][:mapping])
|
122
102
|
@integration_intercom_valid = true
|
123
103
|
else
|
124
|
-
|
104
|
+
FOREST_LOGGER.error 'Cannot setup properly your Intercom integration.'
|
125
105
|
end
|
126
106
|
end
|
127
107
|
end
|
@@ -156,30 +136,43 @@ More info at: https://github.com/ForestAdmin/forest-rails/releases/tag/1.2.0"
|
|
156
136
|
end
|
157
137
|
|
158
138
|
def send_apimap
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
139
|
+
if ForestLiana.secret_key && ForestLiana.secret_key.length != 64
|
140
|
+
FOREST_LOGGER.error "Your secret key does not seem to be correct. " \
|
141
|
+
"Can you check on Forest that you copied it properly in the " \
|
142
|
+
"forest_liana initializer?"
|
143
|
+
else
|
144
|
+
json = JSONAPI::Serializer.serialize(ForestLiana.apimap, {
|
145
|
+
is_collection: true,
|
146
|
+
include: ['actions'],
|
147
|
+
meta: { liana: 'forest-rails', liana_version: liana_version }
|
148
|
+
})
|
149
|
+
|
150
|
+
begin
|
151
|
+
uri = URI.parse("#{forest_url}/forest/apimaps")
|
152
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
153
|
+
http.use_ssl = true if forest_url.start_with?('https')
|
154
|
+
http.start do |client|
|
155
|
+
request = Net::HTTP::Post.new(uri.path)
|
156
|
+
request.body = json.to_json
|
157
|
+
request['Content-Type'] = 'application/json'
|
158
|
+
request['forest-secret-key'] = ForestLiana.secret_key
|
159
|
+
response = client.request(request)
|
160
|
+
|
161
|
+
# NOTICE: HTTP 404 Error
|
162
|
+
if response.is_a?(Net::HTTPNotFound)
|
163
|
+
FOREST_LOGGER.error "Cannot find the project related to the " \
|
164
|
+
"secret key you configured. Can you check on Forest that you " \
|
165
|
+
"copied it properly in the forest_liana initializer?"
|
166
|
+
# NOTICE: HTTP 400 Error
|
167
|
+
elsif response.is_a?(Net::HTTPBadRequest)
|
168
|
+
FOREST_LOGGER.error "An error occured with the apimap sent to " \
|
169
|
+
"Forest. Please contact support@forestadmin.com for further " \
|
170
|
+
"investigations."
|
171
|
+
end
|
179
172
|
end
|
173
|
+
rescue Errno::ECONNREFUSED
|
174
|
+
FOREST_LOGGER.warn "Cannot send the apimap to Forest. Are you online?"
|
180
175
|
end
|
181
|
-
rescue Errno::ECONNREFUSED
|
182
|
-
@logger.warn "Cannot send the apimap to Forest. Are you online?"
|
183
176
|
end
|
184
177
|
end
|
185
178
|
|
@@ -252,8 +245,8 @@ More info at: https://github.com/ForestAdmin/forest-rails/releases/tag/1.2.0"
|
|
252
245
|
if is_deprecated
|
253
246
|
integration[:mapping] = integration[:user_collection]
|
254
247
|
|
255
|
-
|
256
|
-
"now deprecated, please use \"mapping\" attribute."
|
248
|
+
FOREST_LOGGER.warn "Intercom integration attribute \"user_collection\"" \
|
249
|
+
"is now deprecated, please use \"mapping\" attribute."
|
257
250
|
end
|
258
251
|
|
259
252
|
is_deprecated
|
@@ -444,7 +437,7 @@ More info at: https://github.com/ForestAdmin/forest-rails/releases/tag/1.2.0"
|
|
444
437
|
integration[:mapping] =
|
445
438
|
"#{integration[:user_collection]}.#{integration[:user_field]}"
|
446
439
|
|
447
|
-
|
440
|
+
FOREST_LOGGER.warn "Stripe integration attributes \"user_collection\" and " \
|
448
441
|
"\"user_field\" are now deprecated, please use \"mapping\" attribute."
|
449
442
|
end
|
450
443
|
|
@@ -14,16 +14,19 @@ module ForestLiana::Collection
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def action(name, opts = {})
|
17
|
-
opts[:id] = "#{self.collection_name.to_s}.#{name}"
|
17
|
+
opts[:id] = "#{self.collection_name.to_s}.#{name}"
|
18
18
|
opts[:name] = name
|
19
19
|
model.actions << ForestLiana::Model::Action.new(opts)
|
20
20
|
end
|
21
21
|
|
22
22
|
def field(name, opts, &block)
|
23
|
+
opts[:read_only] = true unless opts.has_key?(:read_only)
|
24
|
+
opts[:is_searchable] = false unless opts.has_key?(:is_searchable)
|
25
|
+
|
23
26
|
model.fields << opts.merge({
|
24
27
|
field: name,
|
25
|
-
:'is-read-only' =>
|
26
|
-
:'is-searchable' =>
|
28
|
+
:'is-read-only' => opts[:read_only],
|
29
|
+
:'is-searchable' => opts['is_searchable'],
|
27
30
|
:'is-virtual' => true
|
28
31
|
})
|
29
32
|
|
data/lib/forest_liana/engine.rb
CHANGED
@@ -13,27 +13,39 @@ module ForestLiana
|
|
13
13
|
isolate_namespace ForestLiana
|
14
14
|
|
15
15
|
def configure_forest_cors
|
16
|
-
|
17
|
-
|
16
|
+
begin
|
17
|
+
rack_cors_class = Rack::Cors
|
18
|
+
rack_cors_class = 'Rack::Cors' if Rails::VERSION::MAJOR < 5
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
20
|
+
config.middleware.insert_before 0, rack_cors_class do
|
21
|
+
allow do
|
22
|
+
hostnames = ['localhost:4200', 'app.forestadmin.com',
|
23
|
+
'www.forestadmin.com']
|
24
|
+
hostnames += ENV['CORS_ORIGINS'].split(',') if ENV['CORS_ORIGINS']
|
24
25
|
|
25
|
-
|
26
|
-
|
26
|
+
origins hostnames
|
27
|
+
resource '*', headers: :any, methods: :any
|
28
|
+
end
|
27
29
|
end
|
30
|
+
nil
|
31
|
+
rescue => exception
|
32
|
+
exception
|
28
33
|
end
|
29
34
|
end
|
30
35
|
|
31
|
-
configure_forest_cors unless ENV['FOREST_CORS_DEACTIVATED']
|
36
|
+
error = configure_forest_cors unless ENV['FOREST_CORS_DEACTIVATED']
|
32
37
|
|
33
38
|
config.after_initialize do |app|
|
34
39
|
unless Rails.env.test?
|
40
|
+
if error
|
41
|
+
FOREST_LOGGER.error "Impossible to set the whitelisted Forest " \
|
42
|
+
"domains for CORS constraint:\n#{error}"
|
43
|
+
end
|
44
|
+
|
35
45
|
app.eager_load!
|
36
|
-
|
46
|
+
|
47
|
+
# NOTICE: Do not run the code below on rails g forest_liana:install.
|
48
|
+
Bootstraper.new(app).perform if ForestLiana.secret_key
|
37
49
|
end
|
38
50
|
end
|
39
51
|
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.4.
|
4
|
+
version: 1.4.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sandro Munda
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-11-
|
11
|
+
date: 2016-11-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -189,6 +189,7 @@ files:
|
|
189
189
|
- app/services/forest_liana/value_stat_getter.rb
|
190
190
|
- app/views/layouts/forest_liana/application.html.erb
|
191
191
|
- config/initializers/arel-helpers.rb
|
192
|
+
- config/initializers/logger.rb
|
192
193
|
- config/initializers/time_formats.rb
|
193
194
|
- config/routes.rb
|
194
195
|
- lib/forest_liana.rb
|