models_auditor 1.1.1 → 1.2.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/README.md +9 -0
- data/app/controllers/models_auditor/audit_controller.rb +3 -63
- data/app/models/models_auditor/audit_request.rb +1 -0
- data/app/workers/models_auditor/models_auditor_worker.rb +23 -0
- data/config/config_option_descriptions.yml +1 -3
- data/lib/models_auditor/audit.rb +22 -38
- data/lib/models_auditor/config.rb +5 -5
- data/lib/models_auditor/controller.rb +20 -7
- data/lib/models_auditor/default_formatter.rb +72 -0
- data/lib/models_auditor/version.rb +1 -1
- data/lib/models_auditor.rb +1 -0
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 99a387e69efd7a90352cdf2ef193a8ac885d2f58
|
4
|
+
data.tar.gz: d45f0de4510f98035c96635760bb5a654621b874
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0d501e1c682daae07a70054ab5b23638a00ea71f6dd7c1b05ce7a9af4eaa9f17386b140bc88f5689bfb5b1df214f211c0b84ed60665790ee059a59c97835bf2b
|
7
|
+
data.tar.gz: 48c6ab3335b1b4325a10ffca829b6338cbed273e33410d2da85d22d133a1532e223c5879555ced53e6f5d2d62c973ffd698038e38110ca9ec65c19da41d11354
|
data/README.md
CHANGED
@@ -19,9 +19,11 @@ module ModelsAuditor
|
|
19
19
|
|
20
20
|
respond_to do |f|
|
21
21
|
if ModelsAuditor.config.respond_to_json_enabled
|
22
|
+
formatter = ModelsAuditor.config.log_output_formatter.constantize.new(@collection)
|
23
|
+
|
22
24
|
f.json {
|
23
25
|
render json: {
|
24
|
-
ModelsAuditor.config.json_response_data_key =>
|
26
|
+
ModelsAuditor.config.json_response_data_key => formatter.as_json,
|
25
27
|
ModelsAuditor.config.json_response_meta_key => {
|
26
28
|
per_page: @collection.per_page,
|
27
29
|
total: @collection.total_entries,
|
@@ -77,67 +79,5 @@ module ModelsAuditor
|
|
77
79
|
original.where(id: filtered_requests)
|
78
80
|
end
|
79
81
|
|
80
|
-
def get_relations(record, records)
|
81
|
-
rel_records = records.select do |r|
|
82
|
-
!r.bridge.nil? && r.bridge.any? do |_, v|
|
83
|
-
v_type, v_id = v.to_a[0]
|
84
|
-
v_type.to_s == record.object_type && v_id.to_i == record.object_id.to_i
|
85
|
-
end
|
86
|
-
end
|
87
|
-
rel_records.map do |i|
|
88
|
-
target_info = except_target_class(i.bridge, record.object_type, record.object_id)
|
89
|
-
next if target_info.empty?
|
90
|
-
t_key, klass_with_id = target_info.to_a[0]
|
91
|
-
target_klass, target_id = klass_with_id.to_a[0]
|
92
|
-
i.attributes.slice('id', 'object_type', 'object_id').merge(target: {
|
93
|
-
class: target_klass,
|
94
|
-
foreign_key: t_key,
|
95
|
-
foreign_id: target_id,
|
96
|
-
})
|
97
|
-
end.compact
|
98
|
-
end
|
99
|
-
|
100
|
-
# @return [Array]
|
101
|
-
def except_target_class(bridge, target_class, target_id)
|
102
|
-
target_id = target_id.to_i
|
103
|
-
bridge.select do |_, v|
|
104
|
-
klass, id = v.to_a[0]
|
105
|
-
!(klass.to_s == target_class.to_s && id.to_i == target_id.to_i)
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
# @param [ActiveRecord::Relation|ModelsAuditor::AuditRequest|Array] data
|
110
|
-
def structure_requests_data(data)
|
111
|
-
requests =
|
112
|
-
case data
|
113
|
-
when ActiveRecord::Relation
|
114
|
-
data.to_a
|
115
|
-
when ModelsAuditor::AuditRequest
|
116
|
-
[data]
|
117
|
-
when Array
|
118
|
-
data
|
119
|
-
else
|
120
|
-
raise ArgumentError('Incorrect type of argument `requests`')
|
121
|
-
end
|
122
|
-
|
123
|
-
requests.map do |request|
|
124
|
-
records = request.records
|
125
|
-
{}.tap do |result|
|
126
|
-
changed_models_collection =
|
127
|
-
records
|
128
|
-
.select { |record| record.bridge.nil? }
|
129
|
-
.map do |record|
|
130
|
-
{
|
131
|
-
data: record.attributes.slice('id', 'object_type', 'object_id'),
|
132
|
-
relationships: get_relations(record, records)
|
133
|
-
}
|
134
|
-
end
|
135
|
-
|
136
|
-
result[:request] = request.as_json
|
137
|
-
result[:changes_struct] = changed_models_collection.group_by { |i| i[:data]['object_type'] }
|
138
|
-
result[:all_changes] = records.map(&:as_json)
|
139
|
-
end
|
140
|
-
end
|
141
|
-
end
|
142
82
|
end
|
143
83
|
end
|
@@ -8,6 +8,7 @@ module ModelsAuditor
|
|
8
8
|
self.table_name = ModelsAuditor.config.audit_requests_table_name
|
9
9
|
|
10
10
|
has_many :records, class_name: ModelsAuditor::AuditRecord.name, foreign_key: :request_id, inverse_of: :request
|
11
|
+
accepts_nested_attributes_for :records
|
11
12
|
|
12
13
|
# def as_json(options = nil)
|
13
14
|
# super({include: :records }.merge(options || {}))
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'sidekiq'
|
2
|
+
|
3
|
+
module ModelsAuditor
|
4
|
+
class ModelsAuditorWorker
|
5
|
+
include Sidekiq::Worker
|
6
|
+
|
7
|
+
sidekiq_options queue: 'models_auditor', retry: 2, backtrace: true
|
8
|
+
|
9
|
+
def perform(request_data_json)
|
10
|
+
return unless ModelsAuditor.config.audit_enabled
|
11
|
+
|
12
|
+
ModelsAuditor::AuditRecord.connection.pool.with_connection do
|
13
|
+
request_data = JSON.parse(request_data_json)
|
14
|
+
request = ModelsAuditor::AuditRequest.new(request_data)
|
15
|
+
unless request.save
|
16
|
+
ModelsAuditor.log_error("Couldn't save request record")
|
17
|
+
ModelsAuditor.log_error(request.errors.full_messages)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -3,9 +3,6 @@ connection_namespace: Namespace для конфига базы данн
|
|
3
3
|
audit_migrations_dir: Папка для хранения миграций аудитора
|
4
4
|
audit_records_table_name: Название таблицы для хрянения логов
|
5
5
|
audit_requests_table_name: Название таблицы для хранения информации о запросах, приведших к изменению данных
|
6
|
-
audit_request_changes_only: |-
|
7
|
-
true: Логировать только изменения, производимые через Request
|
8
|
-
false: Логировать любые изменения
|
9
6
|
logger: |-
|
10
7
|
Может принимать объект класса Logger или false
|
11
8
|
Пример:
|
@@ -21,3 +18,4 @@ respond_to_json_enabled: Доступ к логам через json api
|
|
21
18
|
respond_to_html_enabled: Доступ к логам через html
|
22
19
|
json_response_data_key: Ключ с залогированными данными в json ответе
|
23
20
|
json_response_meta_key: Ключ с meta информацией в json ответе
|
21
|
+
log_output_formatter: Класс форматирующий данные логов перед выдачей
|
data/lib/models_auditor/audit.rb
CHANGED
@@ -84,46 +84,30 @@ module ModelsAuditor
|
|
84
84
|
options[:bridge].each_with_object({}) { |(key, model_name), o| o[key] = {model_name => __send__(key)} }
|
85
85
|
end
|
86
86
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
when AUDIT_CHANGES_MODES.include?(mode)
|
98
|
-
current_data
|
99
|
-
else
|
100
|
-
raise ArgumentError.new('Incorrect value of argument audit_type')
|
101
|
-
end
|
102
|
-
|
103
|
-
if request.try(:new_record?) && !request.save
|
104
|
-
ModelsAuditor.log_error("Couldn't save request record")
|
105
|
-
ModelsAuditor.log_error(request.errors.full_messages)
|
106
|
-
return
|
107
|
-
end
|
108
|
-
record =
|
109
|
-
ModelsAuditor::AuditRecord.new(
|
110
|
-
request: request,
|
111
|
-
auditable: self,
|
112
|
-
content: body,
|
113
|
-
action: action,
|
114
|
-
bridge: bridge
|
115
|
-
)
|
116
|
-
unless record.save
|
117
|
-
ModelsAuditor.log_error("Couldn't logged changes of #{self.class.name} id: #{self.try(:id)}")
|
118
|
-
ModelsAuditor.log_error(record.errors.full_messages)
|
119
|
-
end
|
87
|
+
begin
|
88
|
+
if (request_data = store[:audit_request_data]).present?
|
89
|
+
body =
|
90
|
+
case
|
91
|
+
when AUDIT_SNAPSHOT_MODES.include?(mode)
|
92
|
+
ma_eliminate_not_changed_keys(initial_data, current_data)
|
93
|
+
when AUDIT_CHANGES_MODES.include?(mode)
|
94
|
+
current_data
|
95
|
+
else
|
96
|
+
raise ArgumentError.new('Incorrect value of argument audit_type')
|
120
97
|
end
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
98
|
+
|
99
|
+
request_data[:records_attributes] << {
|
100
|
+
object_id: self.id,
|
101
|
+
object_type: self.class.name,
|
102
|
+
content: body,
|
103
|
+
action: action,
|
104
|
+
bridge: bridge
|
105
|
+
}
|
126
106
|
end
|
107
|
+
rescue StandardError => e
|
108
|
+
ModelsAuditor.log_error("Couldn't generate log changes of #{self.class.name} id: #{self.try(:id)}")
|
109
|
+
ModelsAuditor.log_error(e.message)
|
110
|
+
ModelsAuditor.log_error(e.backtrace.take(100).join("\n"))
|
127
111
|
end
|
128
112
|
end
|
129
113
|
|
@@ -6,7 +6,6 @@ module ModelsAuditor
|
|
6
6
|
audit_records_table_name
|
7
7
|
audit_requests_table_name
|
8
8
|
audit_migrations_dir
|
9
|
-
audit_request_changes_only
|
10
9
|
logger
|
11
10
|
records_per_page
|
12
11
|
fake_total_count
|
@@ -15,6 +14,7 @@ module ModelsAuditor
|
|
15
14
|
respond_to_html_enabled
|
16
15
|
json_response_data_key
|
17
16
|
json_response_meta_key
|
17
|
+
log_output_formatter
|
18
18
|
)
|
19
19
|
|
20
20
|
def initialize
|
@@ -47,10 +47,6 @@ module ModelsAuditor
|
|
47
47
|
config: "Logger.new(Rails.root.join('log', 'models_auditor.log'))",
|
48
48
|
val: Logger.new(Rails.root.join('log', 'models_auditor.log'))
|
49
49
|
},
|
50
|
-
audit_request_changes_only: {
|
51
|
-
config: 'true',
|
52
|
-
val: true
|
53
|
-
},
|
54
50
|
records_per_page: {
|
55
51
|
config: '10',
|
56
52
|
val: 10
|
@@ -79,6 +75,10 @@ module ModelsAuditor
|
|
79
75
|
config: "'meta'",
|
80
76
|
val: 'meta'
|
81
77
|
},
|
78
|
+
log_output_formatter: {
|
79
|
+
config: "'ModelsAuditor::DefaultFormatter'",
|
80
|
+
val: 'ModelsAuditor::DefaultFormatter'
|
81
|
+
},
|
82
82
|
}
|
83
83
|
end
|
84
84
|
|
@@ -1,19 +1,32 @@
|
|
1
1
|
module ModelsAuditor
|
2
2
|
module Controller
|
3
3
|
def self.included(base)
|
4
|
-
base.
|
4
|
+
base.around_action :set_models_auditor_request_params
|
5
5
|
end
|
6
6
|
|
7
7
|
protected
|
8
8
|
|
9
9
|
def set_models_auditor_request_params
|
10
|
-
ModelsAuditor.
|
11
|
-
ModelsAuditor
|
10
|
+
if ModelsAuditor.config.audit_enabled
|
11
|
+
ModelsAuditor.store[:audit_request_data] = {
|
12
12
|
user_id: user_for_models_auditor,
|
13
|
-
request_info: info_for_models_auditor
|
14
|
-
|
15
|
-
|
16
|
-
|
13
|
+
request_info: info_for_models_auditor,
|
14
|
+
records_attributes: []
|
15
|
+
}
|
16
|
+
|
17
|
+
yield
|
18
|
+
|
19
|
+
if ModelsAuditor.store[:audit_request_data][:records_attributes].present?
|
20
|
+
begin
|
21
|
+
ModelsAuditor::ModelsAuditorWorker.perform_async(ModelsAuditor.store[:audit_request_data].to_json)
|
22
|
+
rescue StandardError => e
|
23
|
+
ModelsAuditor.log_error(e.message)
|
24
|
+
ModelsAuditor.log_error(e.backtrace.take(100).join("\n"))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
else
|
28
|
+
yield
|
29
|
+
end
|
17
30
|
end
|
18
31
|
|
19
32
|
# Returns the user who is responsible for any changes that occur.
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module ModelsAuditor
|
2
|
+
class DefaultFormatter
|
3
|
+
def initialize(collection)
|
4
|
+
@collection = collection
|
5
|
+
end
|
6
|
+
|
7
|
+
# @param [ActiveRecord::Relation|ModelsAuditor::AuditRequest|Array] data
|
8
|
+
def as_json
|
9
|
+
requests =
|
10
|
+
case @collection
|
11
|
+
when ActiveRecord::Relation
|
12
|
+
@collection.to_a
|
13
|
+
when ModelsAuditor::AuditRequest
|
14
|
+
[@collection]
|
15
|
+
when Array
|
16
|
+
@collection
|
17
|
+
else
|
18
|
+
raise ArgumentError('Incorrect type of argument `requests`')
|
19
|
+
end
|
20
|
+
|
21
|
+
requests.map do |request|
|
22
|
+
records = request.records
|
23
|
+
{}.tap do |result|
|
24
|
+
changed_models_collection =
|
25
|
+
records
|
26
|
+
.select { |record| record.bridge.nil? }
|
27
|
+
.map do |record|
|
28
|
+
{
|
29
|
+
data: record.attributes.slice('id', 'object_type', 'object_id'),
|
30
|
+
relationships: get_relations(record, records)
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
result[:request] = request.as_json
|
35
|
+
result[:changes_struct] = changed_models_collection.group_by { |i| i[:data]['object_type'] }
|
36
|
+
result[:all_changes] = records.map(&:as_json)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
# @return [Array]
|
44
|
+
def except_target_class(bridge, target_class, target_id)
|
45
|
+
target_id = target_id.to_i
|
46
|
+
bridge.select do |_, v|
|
47
|
+
klass, id = v.to_a[0]
|
48
|
+
!(klass.to_s == target_class.to_s && id.to_i == target_id.to_i)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def get_relations(record, records)
|
53
|
+
rel_records = records.select do |r|
|
54
|
+
!r.bridge.nil? && r.bridge.any? do |_, v|
|
55
|
+
v_type, v_id = v.to_a[0]
|
56
|
+
v_type.to_s == record.object_type && v_id.to_i == record.object_id.to_i
|
57
|
+
end
|
58
|
+
end
|
59
|
+
rel_records.map do |i|
|
60
|
+
target_info = except_target_class(i.bridge, record.object_type, record.object_id)
|
61
|
+
next if target_info.empty?
|
62
|
+
t_key, klass_with_id = target_info.to_a[0]
|
63
|
+
target_klass, target_id = klass_with_id.to_a[0]
|
64
|
+
i.attributes.slice('id', 'object_type', 'object_id').merge(target: {
|
65
|
+
class: target_klass,
|
66
|
+
foreign_key: t_key,
|
67
|
+
foreign_id: target_id,
|
68
|
+
})
|
69
|
+
end.compact
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/lib/models_auditor.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: models_auditor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexander Gorbunov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-11-
|
11
|
+
date: 2016-11-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: 1.3.1
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: sidekiq
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 2.17.7
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 2.17.7
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: pry
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -131,6 +145,7 @@ files:
|
|
131
145
|
- app/views/models_auditor/audit/_record.html.erb
|
132
146
|
- app/views/models_auditor/audit/_request.html.erb
|
133
147
|
- app/views/models_auditor/audit/index.html.erb
|
148
|
+
- app/workers/models_auditor/models_auditor_worker.rb
|
134
149
|
- config/config_option_descriptions.yml
|
135
150
|
- config/routes.rb
|
136
151
|
- lib/generators/models_auditor/db_config/USAGE
|
@@ -149,6 +164,7 @@ files:
|
|
149
164
|
- lib/models_auditor/capistrano/tasks/audit_migrations.rake
|
150
165
|
- lib/models_auditor/config.rb
|
151
166
|
- lib/models_auditor/controller.rb
|
167
|
+
- lib/models_auditor/default_formatter.rb
|
152
168
|
- lib/models_auditor/engine.rb
|
153
169
|
- lib/models_auditor/version.rb
|
154
170
|
- lib/tasks/models_auditor_tasks.rake
|