forest_liana 1.3.47 → 1.3.48
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/application_controller.rb +6 -1
- data/app/controllers/forest_liana/associations_controller.rb +7 -3
- data/app/controllers/forest_liana/resources_controller.rb +5 -1
- data/app/controllers/forest_liana/sessions_controller.rb +14 -3
- data/app/controllers/forest_liana/stats_controller.rb +5 -1
- data/app/models/forest_liana/model/action.rb +1 -5
- data/app/services/forest_liana/operator_date_interval_parser.rb +118 -18
- data/app/services/forest_liana/pie_stat_getter.rb +6 -0
- data/lib/forest_liana/bootstraper.rb +22 -1
- data/lib/forest_liana/collection.rb +1 -0
- data/lib/forest_liana/engine.rb +4 -1
- data/lib/forest_liana/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6db1641f295cb1be97c63a55623100e571c14b6d
|
|
4
|
+
data.tar.gz: b2be28e7ba9d66e0dafd86f47cb8ca6826f438ad
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2966c778d6a512d84cd9b3d23edc6a9fc18eca9ea1724509e2c44a1e2a30ca9f6e01ebcf969d9b0e4e45c50b1eaa58b6f3d146891b9d48aecc06762cba6598c2
|
|
7
|
+
data.tar.gz: 2ae9b44ba753511a8c3a14c9c8ebf101975a1ed3a011368e5b45240344c22f9b18ebf826523cd563ababa5b5382005532ed4a50e846396a33586fd70ec0f3d67
|
|
@@ -2,7 +2,12 @@ require 'jwt'
|
|
|
2
2
|
|
|
3
3
|
module ForestLiana
|
|
4
4
|
class ApplicationController < ActionController::Base
|
|
5
|
-
|
|
5
|
+
if Rails::VERSION::MAJOR < 4
|
|
6
|
+
before_filter :authenticate_user_from_jwt
|
|
7
|
+
else
|
|
8
|
+
before_action :authenticate_user_from_jwt
|
|
9
|
+
end
|
|
10
|
+
|
|
6
11
|
wrap_parameters format: [:json] if respond_to?(:wrap_parameters)
|
|
7
12
|
|
|
8
13
|
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
module ForestLiana
|
|
2
2
|
class AssociationsController < ForestLiana::ApplicationController
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
if Rails::VERSION::MAJOR < 4
|
|
4
|
+
before_filter :find_resource
|
|
5
|
+
before_filter :find_association
|
|
6
|
+
else
|
|
7
|
+
before_action :find_resource
|
|
8
|
+
before_action :find_association
|
|
9
|
+
end
|
|
6
10
|
|
|
7
11
|
def index
|
|
8
12
|
getter = HasManyGetter.new(@resource, @association, params)
|
|
@@ -20,9 +20,20 @@ module ForestLiana
|
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
def check_user
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
# NOTICE: Use the ForestUser table for authentication.
|
|
24
|
+
if defined? ForestUser
|
|
25
|
+
user = ForestUser.find_by(email: params['email'])
|
|
26
|
+
return nil if user.blank?
|
|
27
|
+
|
|
28
|
+
if BCrypt::Password.new(user['password_hash']) == params['password']
|
|
29
|
+
user
|
|
30
|
+
end
|
|
31
|
+
# NOTICE: Query Forest server for authentication.
|
|
32
|
+
else
|
|
33
|
+
ForestLiana.allowed_users.find do |allowed_user|
|
|
34
|
+
allowed_user['email'] == params['email'] &&
|
|
35
|
+
BCrypt::Password.new(allowed_user['password']) == params['password']
|
|
36
|
+
end
|
|
26
37
|
end
|
|
27
38
|
end
|
|
28
39
|
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
module ForestLiana
|
|
2
2
|
class StatsController < ForestLiana::ApplicationController
|
|
3
|
-
|
|
3
|
+
if Rails::VERSION::MAJOR < 4
|
|
4
|
+
before_action :find_resource
|
|
5
|
+
else
|
|
6
|
+
before_action :find_resource
|
|
7
|
+
end
|
|
4
8
|
|
|
5
9
|
def show
|
|
6
10
|
case params[:type].try(:downcase)
|
|
@@ -4,7 +4,7 @@ class ForestLiana::Model::Action
|
|
|
4
4
|
include ActiveModel::Serialization
|
|
5
5
|
extend ActiveModel::Naming
|
|
6
6
|
|
|
7
|
-
attr_accessor :name, :endpoint, :http_method, :fields, :redirect
|
|
7
|
+
attr_accessor :id, :name, :endpoint, :http_method, :fields, :redirect
|
|
8
8
|
|
|
9
9
|
def initialize(attributes = {})
|
|
10
10
|
attributes.each do |name, value|
|
|
@@ -15,8 +15,4 @@ class ForestLiana::Model::Action
|
|
|
15
15
|
def persisted?
|
|
16
16
|
false
|
|
17
17
|
end
|
|
18
|
-
|
|
19
|
-
def id
|
|
20
|
-
name
|
|
21
|
-
end
|
|
22
18
|
end
|
|
@@ -1,17 +1,35 @@
|
|
|
1
1
|
module ForestLiana
|
|
2
2
|
class OperatorDateIntervalParser
|
|
3
3
|
PERIODS = {
|
|
4
|
-
yesterday: { duration: 1, period: 'day' },
|
|
5
|
-
lastWeek: { duration: 1, period: 'week' },
|
|
6
|
-
last2Weeks: { duration: 2, period: 'week' },
|
|
7
|
-
lastMonth: { duration: 1, period: 'month' },
|
|
8
|
-
last3Months: { duration: 3, period: 'month' },
|
|
9
|
-
lastYear: { duration: 1, period: 'year' }
|
|
4
|
+
yesterday: { duration: 1, period: 'day' }, # TODO: Remove once new filter protocol is live
|
|
5
|
+
lastWeek: { duration: 1, period: 'week' }, # TODO: Remove once new filter protocol is live
|
|
6
|
+
last2Weeks: { duration: 2, period: 'week' }, # TODO: Remove once new filter protocol is live
|
|
7
|
+
lastMonth: { duration: 1, period: 'month' }, # TODO: Remove once new filter protocol is live
|
|
8
|
+
last3Months: { duration: 3, period: 'month' }, # TODO: Remove once new filter protocol is live
|
|
9
|
+
lastYear: { duration: 1, period: 'year' }, # TODO: Remove once new filter protocol is live
|
|
10
|
+
'$yesterday': { duration: 1, period: 'day' },
|
|
11
|
+
'$previousWeek': { duration: 1, period: 'week' },
|
|
12
|
+
'$previousMonth': { duration: 1, period: 'month' },
|
|
13
|
+
'$previousQuarter': { duration: 3, period: 'month',
|
|
14
|
+
period_of_time: 'quarter' },
|
|
15
|
+
'$previousYear': { duration: 1, period: 'year' },
|
|
16
|
+
'$weekToDate': { duration: 1, period: 'week', to_date: true },
|
|
17
|
+
'$monthToDate': { duration: 1, period: 'month', to_date: true },
|
|
18
|
+
'$quarterToDate': { duration: 3, period: 'month',
|
|
19
|
+
period_of_time: 'quarter', to_date: true },
|
|
20
|
+
'$yearToDate': { duration: 1, period: 'year', to_date: true }
|
|
10
21
|
}
|
|
11
22
|
|
|
12
|
-
PERIODS_FROM_NOW = 'fromNow'
|
|
13
|
-
|
|
14
|
-
|
|
23
|
+
PERIODS_FROM_NOW = 'fromNow' # TODO: Remove once new filter protocol is live
|
|
24
|
+
PERIODS_TODAY_DEPRECATED = 'today' # TODO: Remove once new filter protocol is live
|
|
25
|
+
|
|
26
|
+
PERIODS_PAST = '$past';
|
|
27
|
+
PERIODS_FUTURE = '$future';
|
|
28
|
+
PERIODS_TODAY = '$today';
|
|
29
|
+
|
|
30
|
+
PERIODS_LAST_X_DAYS = /^last(\d+)days$/ # TODO: Remove once new filter protocol is live
|
|
31
|
+
PERIODS_PREVIOUS_X_DAYS = /^\$previous(\d+)Days$/;
|
|
32
|
+
PERIODS_X_DAYS_TO_DATE = /^\$(\d+)DaysToDate$/;
|
|
15
33
|
|
|
16
34
|
def initialize(value)
|
|
17
35
|
@value = value
|
|
@@ -20,68 +38,150 @@ module ForestLiana
|
|
|
20
38
|
def is_interval_date_value
|
|
21
39
|
return false if @value.nil?
|
|
22
40
|
return true if PERIODS[@value.to_sym]
|
|
23
|
-
return true if [PERIODS_FROM_NOW, PERIODS_TODAY].include? @value
|
|
24
41
|
|
|
42
|
+
# TODO: Remove once new filter protocol is live
|
|
43
|
+
return true if [PERIODS_FROM_NOW, PERIODS_TODAY_DEPRECATED].include? @value
|
|
44
|
+
|
|
45
|
+
return true if [PERIODS_PAST, PERIODS_FUTURE, PERIODS_TODAY].include? @value
|
|
46
|
+
|
|
47
|
+
# TODO: Remove once new filter protocol is live
|
|
25
48
|
match = PERIODS_LAST_X_DAYS.match(@value)
|
|
26
49
|
return true if match && match[1]
|
|
27
50
|
|
|
51
|
+
match = PERIODS_PREVIOUS_X_DAYS.match(@value)
|
|
52
|
+
return true if match && match[1]
|
|
53
|
+
|
|
54
|
+
match = PERIODS_X_DAYS_TO_DATE.match(@value)
|
|
55
|
+
return true if match && match[1]
|
|
56
|
+
|
|
28
57
|
false
|
|
29
58
|
end
|
|
30
59
|
|
|
31
60
|
def has_previous_interval
|
|
32
61
|
return false if @value.nil?
|
|
33
62
|
return true if PERIODS[@value.to_sym]
|
|
63
|
+
|
|
64
|
+
# TODO: Remove once new filter protocol is live
|
|
65
|
+
return true if PERIODS_TODAY_DEPRECATED == @value
|
|
66
|
+
|
|
34
67
|
return true if PERIODS_TODAY == @value
|
|
35
68
|
|
|
69
|
+
# TODO: Remove once new filter protocol is live
|
|
36
70
|
match = PERIODS_LAST_X_DAYS.match(@value)
|
|
37
71
|
return true if match && match[1]
|
|
38
72
|
|
|
73
|
+
match = PERIODS_PREVIOUS_X_DAYS.match(@value)
|
|
74
|
+
return true if match && match[1]
|
|
75
|
+
|
|
76
|
+
match = PERIODS_X_DAYS_TO_DATE.match(@value)
|
|
77
|
+
return true if match && match[1]
|
|
78
|
+
|
|
39
79
|
false
|
|
40
80
|
end
|
|
41
81
|
|
|
42
82
|
def get_interval_date_filter
|
|
43
83
|
return nil unless is_interval_date_value()
|
|
44
84
|
|
|
85
|
+
# TODO: Remove once new filter protocol is live
|
|
45
86
|
return ">= '#{Time.now}'" if @value == PERIODS_FROM_NOW
|
|
46
87
|
|
|
88
|
+
return ">= '#{Time.now}'" if @value == PERIODS_FUTURE
|
|
89
|
+
return "<= '#{Time.now}'" if @value == PERIODS_PAST
|
|
90
|
+
|
|
91
|
+
# TODO: Remove once new filter protocol is live
|
|
92
|
+
if @value == PERIODS_TODAY_DEPRECATED
|
|
93
|
+
return "BETWEEN '#{Time.now.beginning_of_day}' AND " +
|
|
94
|
+
"'#{Time.now.end_of_day}'"
|
|
95
|
+
end
|
|
96
|
+
|
|
47
97
|
if @value == PERIODS_TODAY
|
|
48
98
|
return "BETWEEN '#{Time.now.beginning_of_day}' AND " +
|
|
49
99
|
"'#{Time.now.end_of_day}'"
|
|
50
100
|
end
|
|
51
101
|
|
|
102
|
+
# TODO: Remove once new filter protocol is live
|
|
52
103
|
match = PERIODS_LAST_X_DAYS.match(@value)
|
|
53
104
|
if match && match[1]
|
|
54
105
|
return "BETWEEN '#{Integer(match[1]).day.ago.beginning_of_day}'" +
|
|
55
106
|
" AND '#{1.day.ago.end_of_day}'"
|
|
56
107
|
end
|
|
57
108
|
|
|
109
|
+
match = PERIODS_PREVIOUS_X_DAYS.match(@value)
|
|
110
|
+
if match && match[1]
|
|
111
|
+
return "BETWEEN '#{Integer(match[1]).day.ago.beginning_of_day}'" +
|
|
112
|
+
" AND '#{1.day.ago.end_of_day}'"
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
match = PERIODS_X_DAYS_TO_DATE.match(@value)
|
|
116
|
+
if match && match[1]
|
|
117
|
+
return "BETWEEN '#{(Integer(match[1]) - 1).day.ago.beginning_of_day}'" +
|
|
118
|
+
" AND '#{Time.now}'"
|
|
119
|
+
end
|
|
120
|
+
|
|
58
121
|
duration = PERIODS[@value.to_sym][:duration]
|
|
59
122
|
period = PERIODS[@value.to_sym][:period]
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
123
|
+
period_of_time = PERIODS[@value.to_sym][:period_of_time] ||
|
|
124
|
+
PERIODS[@value.to_sym][:period]
|
|
125
|
+
to_date = PERIODS[@value.to_sym][:to_date]
|
|
126
|
+
|
|
127
|
+
if to_date
|
|
128
|
+
from = Time.now.send("beginning_of_#{period_of_time}")
|
|
129
|
+
to = Time.now
|
|
130
|
+
else
|
|
131
|
+
from = duration.send(period).ago.send("beginning_of_#{period_of_time}")
|
|
132
|
+
to = 1.send(period).ago.send("end_of_#{period_of_time}")
|
|
133
|
+
end
|
|
63
134
|
"BETWEEN '#{from}' AND '#{to}'"
|
|
64
135
|
end
|
|
65
136
|
|
|
66
137
|
def get_interval_date_filter_for_previous_interval
|
|
67
138
|
return nil unless has_previous_interval()
|
|
68
139
|
|
|
140
|
+
# TODO: Remove once new filter protocol is live
|
|
141
|
+
if @value == PERIODS_TODAY_DEPRECATED
|
|
142
|
+
return "BETWEEN '#{1.day.ago.beginning_of_day}' AND " +
|
|
143
|
+
"'#{1.day.ago.end_of_day}'"
|
|
144
|
+
end
|
|
145
|
+
|
|
69
146
|
if @value == PERIODS_TODAY
|
|
70
147
|
return "BETWEEN '#{1.day.ago.beginning_of_day}' AND " +
|
|
71
148
|
"'#{1.day.ago.end_of_day}'"
|
|
72
149
|
end
|
|
73
150
|
|
|
151
|
+
# TODO: Remove once new filter protocol is live
|
|
74
152
|
match = PERIODS_LAST_X_DAYS.match(@value)
|
|
75
153
|
if match && match[1]
|
|
76
|
-
return "BETWEEN '#{Integer(match[1] * 2).day.ago.beginning_of_day}'" +
|
|
77
|
-
" AND '#{Integer(match[1]).day.ago.end_of_day}'"
|
|
154
|
+
return "BETWEEN '#{(Integer(match[1]) * 2).day.ago.beginning_of_day}'" +
|
|
155
|
+
" AND '#{(Integer(match[1]) + 1).day.ago.end_of_day}'"
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
match = PERIODS_PREVIOUS_X_DAYS.match(@value)
|
|
159
|
+
if match && match[1]
|
|
160
|
+
return "BETWEEN '#{(Integer(match[1]) * 2).day.ago.beginning_of_day}'" +
|
|
161
|
+
" AND '#{(Integer(match[1]) + 1).day.ago.end_of_day}'"
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
match = PERIODS_X_DAYS_TO_DATE.match(@value)
|
|
165
|
+
if match && match[1]
|
|
166
|
+
return "BETWEEN '#{((Integer(match[1]) * 2) - 1).day.ago.beginning_of_day}'" +
|
|
167
|
+
" AND '#{Integer(match[1]).day.ago}'"
|
|
78
168
|
end
|
|
79
169
|
|
|
80
170
|
duration = PERIODS[@value.to_sym][:duration]
|
|
81
171
|
period = PERIODS[@value.to_sym][:period]
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
172
|
+
period_of_time = PERIODS[@value.to_sym][:period_of_time] ||
|
|
173
|
+
PERIODS[@value.to_sym][:period]
|
|
174
|
+
to_date = PERIODS[@value.to_sym][:to_date]
|
|
175
|
+
|
|
176
|
+
if to_date
|
|
177
|
+
from = (duration).send(period).ago
|
|
178
|
+
.send("beginning_of_#{period_of_time}")
|
|
179
|
+
to = (duration).send(period).ago
|
|
180
|
+
else
|
|
181
|
+
from = (duration * 2).send(period).ago
|
|
182
|
+
.send("beginning_of_#{period_of_time}")
|
|
183
|
+
to = (1 + duration).send(period).ago.send("end_of_#{period_of_time}")
|
|
184
|
+
end
|
|
85
185
|
"BETWEEN '#{from}' AND '#{to}'"
|
|
86
186
|
end
|
|
87
187
|
end
|
|
@@ -37,6 +37,12 @@ module ForestLiana
|
|
|
37
37
|
.order("#{@params[:aggregate].downcase}_#{field} DESC")
|
|
38
38
|
.send(@params[:aggregate].downcase, @params[:aggregate_field])
|
|
39
39
|
.map do |k, v|
|
|
40
|
+
# NOTICE: Display the enum name instead of a integer if "enum" type
|
|
41
|
+
if @resource.respond_to?(:defined_enums) &&
|
|
42
|
+
@resource.defined_enums.has_key?(@params[:group_by_field])
|
|
43
|
+
k = @resource.defined_enums[@params[:group_by_field]].invert[k]
|
|
44
|
+
end
|
|
45
|
+
|
|
40
46
|
{ key: k, value: v }
|
|
41
47
|
end
|
|
42
48
|
|
|
@@ -45,16 +45,36 @@ More info at: https://github.com/ForestAdmin/forest-rails/releases/tag/1.2.0"
|
|
|
45
45
|
|
|
46
46
|
private
|
|
47
47
|
|
|
48
|
+
def fetch_sti_models(model)
|
|
49
|
+
type_field = model.columns.find {|c| c.name == 'type' }
|
|
50
|
+
if type_field
|
|
51
|
+
model.descendants.each do |sti_model|
|
|
52
|
+
if analyze_model?(sti_model)
|
|
53
|
+
ForestLiana.models << sti_model
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
48
59
|
def analyze_model?(model)
|
|
49
60
|
return model && model.table_exists? && !SchemaUtils.habtm?(model) &&
|
|
50
61
|
SchemaUtils.model_included?(model)
|
|
51
62
|
end
|
|
52
63
|
|
|
53
64
|
def fetch_models
|
|
54
|
-
ActiveRecord::Base.subclasses.each
|
|
65
|
+
ActiveRecord::Base.subclasses.each {|model| fetch_model(model)}
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def fetch_model(model)
|
|
69
|
+
if model.abstract_class?
|
|
70
|
+
model.descendants.each {|submodel| fetch_model(submodel)}
|
|
71
|
+
else
|
|
72
|
+
fetch_sti_models(model) if model.try(:table_exists?)
|
|
73
|
+
|
|
55
74
|
if analyze_model?(model)
|
|
56
75
|
ForestLiana.models << model
|
|
57
76
|
end
|
|
77
|
+
|
|
58
78
|
end
|
|
59
79
|
end
|
|
60
80
|
|
|
@@ -267,6 +287,7 @@ More info at: https://github.com/ForestAdmin/forest-rails/releases/tag/1.2.0"
|
|
|
267
287
|
],
|
|
268
288
|
actions: [
|
|
269
289
|
ForestLiana::Model::Action.new({
|
|
290
|
+
id: 'stripe.Refund',
|
|
270
291
|
name: 'Refund',
|
|
271
292
|
endpoint: '/forest/stripe_payments/refunds'
|
|
272
293
|
})
|
data/lib/forest_liana/engine.rb
CHANGED
|
@@ -12,7 +12,10 @@ module ForestLiana
|
|
|
12
12
|
class Engine < ::Rails::Engine
|
|
13
13
|
isolate_namespace ForestLiana
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
rack_cors_class = Rack::Cors
|
|
16
|
+
rack_cors_class = 'Rack::Cors' if Rails::VERSION::MAJOR < 5
|
|
17
|
+
|
|
18
|
+
config.middleware.insert_before 0, rack_cors_class do
|
|
16
19
|
allow do
|
|
17
20
|
hostnames = ['localhost:4200', 'app.forestadmin.com',
|
|
18
21
|
'www.forestadmin.com']
|
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.3.
|
|
4
|
+
version: 1.3.48
|
|
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-10-
|
|
11
|
+
date: 2016-10-28 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|