glib-web 4.32.0 → 4.33.0
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/helpers/glib/json_ui/view_builder/charts.rb +2 -0
- data/app/views/json_ui/garage/views/charts.json.jbuilder +34 -0
- data/lib/glib/json_crawler/action_crawlers/action_http.rb +1 -0
- data/lib/glib/json_crawler/action_crawlers/forms_submit.rb +2 -0
- data/lib/glib/json_crawler/http.rb +4 -4
- data/lib/glib/json_crawler/router.rb +35 -5
- data/lib/glib/snapshot.rb +93 -19
- data/lib/glib/test_helpers.rb +11 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3500da71e998b625c15ef1a41519581ed5d52d9dd9562a3e031e08d16aa2908c
|
4
|
+
data.tar.gz: 6f781cafa2ffe0cacfe1c7e31656415b2699bd19af4f9149614a5c229f60d94e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 31478adf1a4abdd83df77febe25c6454ebdf66908ecef04b34cb4a48746878a8e0e058184c3cb093c7c4526831b948c539e79d88330c52a6a722fb5be885b4cc
|
7
|
+
data.tar.gz: 97f3164d075437ccb1bac37a6d0bea555ad1ec1b9a7b9870fb1d37a3619cc7a5a361a6684e0a412488d406da3c86dfa90416f7713445ead43bd9c355e18e9deb
|
@@ -138,6 +138,40 @@ else
|
|
138
138
|
plugins: default_plugins,
|
139
139
|
colors: ['#7A71F4', '#53B3E4', 'skyblue'], legend: { override: true }
|
140
140
|
|
141
|
+
|
142
|
+
scroll.h2 text: 'Column chart (Right-to-left)'
|
143
|
+
scroll.charts_column dataGroups: [
|
144
|
+
-> do
|
145
|
+
json.title 'Data 1'
|
146
|
+
|
147
|
+
points = {
|
148
|
+
'Hotel One' => 10,
|
149
|
+
'Hotel Two' => 16,
|
150
|
+
'Hotel Three' => 18,
|
151
|
+
}
|
152
|
+
json.points points
|
153
|
+
end,
|
154
|
+
-> do
|
155
|
+
json.title 'Data 2'
|
156
|
+
|
157
|
+
points = {
|
158
|
+
'Hotel One' => 24,
|
159
|
+
'Hotel Two' => 22,
|
160
|
+
}
|
161
|
+
json.points points
|
162
|
+
end,
|
163
|
+
-> do
|
164
|
+
json.title 'Data 3'
|
165
|
+
|
166
|
+
points = {
|
167
|
+
'Hotel One' => 20,
|
168
|
+
'Hotel Two' => 23,
|
169
|
+
}
|
170
|
+
json.points points
|
171
|
+
end
|
172
|
+
],
|
173
|
+
indexAxis: 'y', horizontalStacked: true,
|
174
|
+
colors: ['#7A71F4', '#53B3E4', 'red'], legend: { override: true }
|
141
175
|
scroll.h2 text: 'Column chart (Stacked)'
|
142
176
|
scroll.charts_column stacked: true, dataGroups: [
|
143
177
|
-> do
|
@@ -4,6 +4,7 @@ module Glib
|
|
4
4
|
def initialize(method, http, args, controller)
|
5
5
|
@http = http
|
6
6
|
json = @http.send(method, args['url'], controller, args.fetch('formData', {}))
|
7
|
+
@http.router.http_actions.add([args['action'], args['url'], args.fetch('formData', {})])
|
7
8
|
perform(json['onResponse'])
|
8
9
|
end
|
9
10
|
end
|
@@ -76,11 +76,13 @@ module Glib
|
|
76
76
|
case method
|
77
77
|
when :patch, :put
|
78
78
|
json = @http.patch url, action, params
|
79
|
+
@http.router.http_actions.add([action, url, params])
|
79
80
|
perform(json['onResponse'])
|
80
81
|
when :post
|
81
82
|
if (groups = form_post_param_groups)
|
82
83
|
groups.each do |group_params|
|
83
84
|
json = @http.post url, action, group_params
|
85
|
+
@http.router.http_actions.add([action, url, group_params])
|
84
86
|
perform(json['onResponse'])
|
85
87
|
end
|
86
88
|
else
|
@@ -24,19 +24,19 @@ module Glib
|
|
24
24
|
fetch(:get, url, action, params, inspect_result)
|
25
25
|
end
|
26
26
|
|
27
|
-
def post(url, action, params)
|
27
|
+
def post(url, action, params, inspect_result = true)
|
28
28
|
fetch(:post, url, action, params)
|
29
29
|
end
|
30
30
|
|
31
|
-
def patch(url, action, params)
|
31
|
+
def patch(url, action, params, inspect_result = true)
|
32
32
|
fetch(:patch, url, action, params)
|
33
33
|
end
|
34
34
|
|
35
|
-
def put(url, action, params)
|
35
|
+
def put(url, action, params, inspect_result = true)
|
36
36
|
fetch(:put, url, action, params)
|
37
37
|
end
|
38
38
|
|
39
|
-
def delete(url, action, params = {})
|
39
|
+
def delete(url, action, params = {}, inspect_result = true)
|
40
40
|
fetch(:delete, url, action, {})
|
41
41
|
end
|
42
42
|
|
@@ -1,7 +1,9 @@
|
|
1
1
|
module Glib
|
2
2
|
module JsonCrawler
|
3
3
|
class Router
|
4
|
-
attr_reader :read_only_actions
|
4
|
+
attr_reader :read_only_actions # deprecated
|
5
|
+
attr_reader :logger, :last_log, :deferred_actions
|
6
|
+
attr_reader :http_actions
|
5
7
|
attr_accessor :host
|
6
8
|
|
7
9
|
def log(action, url, response = nil)
|
@@ -46,6 +48,7 @@ module Glib
|
|
46
48
|
@logger = ''
|
47
49
|
@visitor = Glib::Json::Traversal::Visitor.new(crawler_test: true)
|
48
50
|
@read_only_actions = Set.new
|
51
|
+
@http_actions = Set.new
|
49
52
|
# default rails's development host
|
50
53
|
@host ||= 'localhost:3000'
|
51
54
|
@page_specs = []
|
@@ -72,7 +75,7 @@ module Glib
|
|
72
75
|
end
|
73
76
|
end
|
74
77
|
|
75
|
-
@read_only_actions.replace(@read_only_actions.sort_by { |e| e[1].to_s })
|
78
|
+
# @read_only_actions.replace(@read_only_actions.sort_by { |e| e[1].to_s })
|
76
79
|
end
|
77
80
|
|
78
81
|
def process_action(http, spec)
|
@@ -85,14 +88,16 @@ module Glib
|
|
85
88
|
@depth += 1
|
86
89
|
case action
|
87
90
|
when 'initiate_navigation'
|
88
|
-
@read_only_actions.add([action, params['url']])
|
91
|
+
# @read_only_actions.add([action, params['url']])
|
92
|
+
http_actions.add([action, params['url']])
|
89
93
|
JsonCrawler::NavInitiate.new(http, params, action)
|
90
94
|
when 'runMultiple-v1', 'runMultiple'
|
91
95
|
JsonCrawler::RunMultiple.new(http, params, action)
|
92
96
|
when 'windows/open-v1', 'dialogs/open-v1', 'windows/reload-v1', 'windows/open',
|
93
97
|
'dialogs/open', 'windows/reload', 'windows/openWeb', 'windows/openWeb-v1'
|
94
98
|
if allowed?(params['url'])
|
95
|
-
@read_only_actions.add([action, params['url']])
|
99
|
+
# @read_only_actions.add([action, params['url']])
|
100
|
+
http_actions.add([action, params['url']])
|
96
101
|
JsonCrawler::WindowsOpen.new(http, params, action)
|
97
102
|
else
|
98
103
|
self.log action, params['url']
|
@@ -118,7 +123,8 @@ module Glib
|
|
118
123
|
'http/delete',
|
119
124
|
'dialogs/oauth'
|
120
125
|
].include?(action)
|
121
|
-
@read_only_actions.add([action, params['url']])
|
126
|
+
# @read_only_actions.add([action, params['url']])
|
127
|
+
http_actions.add([action, params['url']])
|
122
128
|
end
|
123
129
|
self.log action, params['url']
|
124
130
|
end
|
@@ -130,6 +136,7 @@ module Glib
|
|
130
136
|
@visitor.forms.last
|
131
137
|
end
|
132
138
|
|
139
|
+
# deprecated
|
133
140
|
def follow(http, target_routers)
|
134
141
|
if !target_routers.is_a?(Array)
|
135
142
|
target_routers = [target_routers]
|
@@ -147,6 +154,29 @@ module Glib
|
|
147
154
|
end
|
148
155
|
end
|
149
156
|
|
157
|
+
def follow_v2(http, crawler_actions)
|
158
|
+
@depth += 1
|
159
|
+
crawler_actions.each do |crawler_action|
|
160
|
+
action, url, params = crawler_action
|
161
|
+
|
162
|
+
params = JSON.parse(params) if params.is_a?(String)
|
163
|
+
params ||= {}
|
164
|
+
|
165
|
+
case action.to_s.downcase
|
166
|
+
when 'http/post-v1', 'forms/post'
|
167
|
+
http.post(url, action, params, false)
|
168
|
+
when 'http/patch-v1', 'forms/patch'
|
169
|
+
http.patch(url, action, params, false)
|
170
|
+
when 'http/put-v1', 'forms/put'
|
171
|
+
http.put(url, action, params, false)
|
172
|
+
when 'http/delete-v1'
|
173
|
+
http.delete(url, action, params, false)
|
174
|
+
else
|
175
|
+
http.get(url, action, params, false)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
150
180
|
def crawl_multiple(views, block)
|
151
181
|
@visitor.traverse_multiple views, block
|
152
182
|
end
|
data/lib/glib/snapshot.rb
CHANGED
@@ -17,6 +17,45 @@ module Glib
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
+
def where_snapshots(user: nil, field: nil, action: nil, association: nil, association_action: nil, like: nil)
|
21
|
+
query = snapshots
|
22
|
+
|
23
|
+
if user.present? && !user.is_a?(String)
|
24
|
+
query = query.where(user_id: user.id, user_type: user.class.to_s)
|
25
|
+
elsif user.present? && user.is_a?(String)
|
26
|
+
query = query.where("metadata ->> 'user' = ?", user)
|
27
|
+
end
|
28
|
+
|
29
|
+
if field.present?
|
30
|
+
query = query.where("metadata -> 'diff' ->> 'item' LIKE ?", "%#{field}%")
|
31
|
+
end
|
32
|
+
|
33
|
+
if action.present?
|
34
|
+
query = query.where("metadata ->> 'action' = ?", action)
|
35
|
+
end
|
36
|
+
|
37
|
+
if association.present?
|
38
|
+
query = query.where("metadata -> 'diff' -> 'associations' -> '#{association}' -> 0 IS NOT NULL")
|
39
|
+
end
|
40
|
+
|
41
|
+
if association_action.present?
|
42
|
+
raise ArgumentError.new('association_action expect association to be present') if association.blank?
|
43
|
+
|
44
|
+
known_actions = {
|
45
|
+
'create' => '+',
|
46
|
+
'destroy' => '-',
|
47
|
+
'update' => '~'
|
48
|
+
}
|
49
|
+
query = query.where("metadata -> 'diff' -> 'associations' ->> '#{association}' LIKE ?", "%\"#{known_actions[association_action.to_s]}\"%")
|
50
|
+
end
|
51
|
+
|
52
|
+
if like.present?
|
53
|
+
query = query.where("metadata ->> 'diff' LIKE ?", "%#{like}%")
|
54
|
+
end
|
55
|
+
|
56
|
+
query.to_a
|
57
|
+
end
|
58
|
+
|
20
59
|
# information need to be store:
|
21
60
|
# - action: create, update, destroy
|
22
61
|
# - track changes
|
@@ -33,16 +72,20 @@ module Glib
|
|
33
72
|
diff: diff,
|
34
73
|
version: version
|
35
74
|
}
|
75
|
+
snapshot_obj = {
|
76
|
+
identifier: "#{self.class.to_s.underscore}_#{id}_version_#{version}",
|
77
|
+
user: user,
|
78
|
+
metadata: metadata
|
79
|
+
}
|
80
|
+
|
81
|
+
if user.is_a?(String)
|
82
|
+
metadata[:user] = user
|
83
|
+
snapshot_obj.delete(:user)
|
84
|
+
end
|
36
85
|
|
37
86
|
# dont create version if same as before
|
38
87
|
if !same_as_before?
|
39
|
-
|
40
|
-
result = create_snapshot!(
|
41
|
-
identifier: "#{self.class.to_s.underscore}_#{id}_version_#{version}",
|
42
|
-
user: user,
|
43
|
-
metadata: metadata
|
44
|
-
)
|
45
|
-
|
88
|
+
result = create_snapshot!(**snapshot_obj)
|
46
89
|
remove_old_snapshot if result.present?
|
47
90
|
end
|
48
91
|
end
|
@@ -62,11 +105,14 @@ module Glib
|
|
62
105
|
default_ignored_keys = ['updated_at', 'created_at']
|
63
106
|
ignore_keys = default_ignored_keys
|
64
107
|
|
65
|
-
if !
|
108
|
+
if !watched_keys_for_snapshot.nil?
|
66
109
|
ignored_keys_for_snapshot = attributes.except(*watched_keys_for_snapshot).keys
|
67
110
|
ignore_keys = (default_ignored_keys + ignored_keys_for_snapshot.map(&:to_s)).uniq
|
68
111
|
end
|
69
112
|
|
113
|
+
# always watch column with name *id
|
114
|
+
ignore_keys.filter! { |key| !key.ends_with?('id') || key != 'id' }
|
115
|
+
|
70
116
|
if snapshot.present?
|
71
117
|
item, associations = snapshot.fetch_reified_items
|
72
118
|
else
|
@@ -80,6 +126,11 @@ module Glib
|
|
80
126
|
|
81
127
|
obj['associations'] = associations_for_snapshot.reduce({}) do |prev, curr|
|
82
128
|
first_record_off_same_collection = send(curr).first
|
129
|
+
|
130
|
+
if !first_record_off_same_collection.respond_to?(:watched_keys_for_snapshot) && !first_record_off_same_collection.nil?
|
131
|
+
raise NotImplementedError, "please add method 'watched_keys_for_snapshot' to #{first_record_off_same_collection.class}"
|
132
|
+
end
|
133
|
+
|
83
134
|
association_ignored_keys =
|
84
135
|
if !first_record_off_same_collection.try(:watched_keys_for_snapshot).nil?
|
85
136
|
assoc_ignore_keys = first_record_off_same_collection.attributes.except(*first_record_off_same_collection.watched_keys_for_snapshot).keys.map(&:to_s)
|
@@ -88,16 +139,37 @@ module Glib
|
|
88
139
|
default_ignored_keys
|
89
140
|
end
|
90
141
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
142
|
+
# always watch column with name *id
|
143
|
+
association_ignored_keys.filter! { |key| !key.ends_with?('id') || key != 'id' }
|
144
|
+
|
145
|
+
# attrs_before = (associations[curr] || []).map { |record| record.attributes.except(*association_ignored_keys) }
|
146
|
+
# attrs_now = send(curr).order(id: :asc).map { |record| record.attributes.except(*association_ignored_keys) }
|
147
|
+
|
148
|
+
before = (associations[curr] || [])
|
149
|
+
now = send(curr).order(id: :asc)
|
150
|
+
|
151
|
+
if before.blank?
|
152
|
+
prev.merge(curr.to_s => ::Hashdiff.diff([], now.map { |record| record.attributes.except(*association_ignored_keys) }))
|
153
|
+
else
|
154
|
+
diff = before.map.with_index do |record_before, index|
|
155
|
+
record_now = now.find_by(id: record_before.id)
|
156
|
+
if record_now.blank?
|
157
|
+
['-', "[#{index}]", record_before.attributes.except(*association_ignored_keys)]
|
158
|
+
elsif record_now.present?
|
159
|
+
next if Hashdiff.diff(record_before.attributes.except(*association_ignored_keys), record_now.attributes.except(*association_ignored_keys)).blank?
|
160
|
+
['~', "[#{index}]", record_before.attributes.except(*association_ignored_keys), record_now.attributes.except(*association_ignored_keys)]
|
161
|
+
end
|
162
|
+
end.compact_blank
|
163
|
+
|
164
|
+
diff2 = now.map.with_index do |record_now, index|
|
165
|
+
record_before = before.detect { |record| record.id == record_now.id }
|
166
|
+
if record_before.blank?
|
167
|
+
['+', "[#{index}]", record_now.attributes.except(*association_ignored_keys)]
|
168
|
+
end
|
169
|
+
end.compact_blank
|
170
|
+
|
171
|
+
prev.merge(curr.to_s => (diff + diff2))
|
172
|
+
end
|
101
173
|
end
|
102
174
|
|
103
175
|
obj
|
@@ -124,6 +196,8 @@ module Glib
|
|
124
196
|
end
|
125
197
|
|
126
198
|
def remove_old_snapshot
|
199
|
+
return if max_snapshots.nil?
|
200
|
+
|
127
201
|
newest_ids = snapshots.order(id: :desc).limit(max_snapshots).ids
|
128
202
|
return unless newest_ids.size >= max_snapshots
|
129
203
|
|
@@ -131,7 +205,7 @@ module Glib
|
|
131
205
|
end
|
132
206
|
|
133
207
|
def watched_keys_for_snapshot
|
134
|
-
|
208
|
+
raise NotImplementedError, "please add method 'watched_keys_for_snapshot' to #{self.class}"
|
135
209
|
end
|
136
210
|
|
137
211
|
def associations_for_snapshot
|
data/lib/glib/test_helpers.rb
CHANGED
@@ -36,7 +36,7 @@ module Glib
|
|
36
36
|
assert_equal JSON.parse(expected), JSON.parse(result), "Result mismatch! #{__git_is_available? ? `git diff #{__controller_log_dir}/#{__controller_log_file}` : ''}"
|
37
37
|
end
|
38
38
|
|
39
|
-
def crawl_json_pages(user, check_result: true, log_file: nil, &block)
|
39
|
+
def crawl_json_pages(user, check_result: true, log_file: nil, dump_actions: false, &block)
|
40
40
|
__execute_crawler(user, check_result: true) do |router, http|
|
41
41
|
path = user[:path] ? "#{user[:path]}?format=json" : '/users/me?format=json&redirect=default'
|
42
42
|
router.host = HOST
|
@@ -47,6 +47,16 @@ module Glib
|
|
47
47
|
'url' => user[:url] || "http://#{HOST}#{path}"
|
48
48
|
}
|
49
49
|
)
|
50
|
+
|
51
|
+
if dump_actions
|
52
|
+
csv_string = router.http_actions.map do |row|
|
53
|
+
action, url, params = row
|
54
|
+
[action, url, JSON.generate(params)].to_csv
|
55
|
+
end.join
|
56
|
+
filename = "#{user[:email]}[#{user[:device]}][#{user[:version] || 'current'}].csv"
|
57
|
+
filepath = File.join(__crawler_log_dir, filename)
|
58
|
+
File.write(filepath, csv_string)
|
59
|
+
end
|
50
60
|
end
|
51
61
|
end
|
52
62
|
|