models_auditor 1.1.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e3cc83c5ea9096c99e6455aaaf01e7a58c016f16
4
- data.tar.gz: a462f33b2f8bf243c2cd1dcaefa9983da0a71f18
3
+ metadata.gz: 99a387e69efd7a90352cdf2ef193a8ac885d2f58
4
+ data.tar.gz: d45f0de4510f98035c96635760bb5a654621b874
5
5
  SHA512:
6
- metadata.gz: caa26da0c5eb6ceb89d71f392788428f5e024ab345ec8a33c489aee240bdd7dc3bdf6496042661dd30721e1ee4ec9466eae7af63479ea6dc53e534293e995eb8
7
- data.tar.gz: c9131493861ee112b1654e8ad441a9ccaa485baa37f620ac62ba34c987690997b360460075a5218ff1f96a76a5095907ed79700d34867ea19be38a266ccae25d
6
+ metadata.gz: 0d501e1c682daae07a70054ab5b23638a00ea71f6dd7c1b05ce7a9af4eaa9f17386b140bc88f5689bfb5b1df214f211c0b84ed60665790ee059a59c97835bf2b
7
+ data.tar.gz: 48c6ab3335b1b4325a10ffca829b6338cbed273e33410d2da85d22d133a1532e223c5879555ced53e6f5d2d62c973ffd698038e38110ca9ec65c19da41d11354
data/README.md CHANGED
@@ -33,6 +33,15 @@
33
33
  6. **Apply migrations to the audit database**
34
34
 
35
35
  `rake db:audit:migrate`
36
+
37
+ 7. **Add to sidekiq config config/sidekiq.yml**
38
+
39
+ ```yaml
40
+ ...
41
+ :queues:
42
+ ...
43
+ - models_auditor
44
+ ```
36
45
 
37
46
  ## Usages
38
47
 
@@ -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 => structure_requests_data(@collection),
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: Класс форматирующий данные логов перед выдачей
@@ -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
- Thread.new do
88
- begin
89
- log_anyway = !ModelsAuditor.config.audit_request_changes_only
90
- if store[:audit_request] || log_anyway
91
- (store[:audit_mutex] ||= Mutex.new).synchronize do
92
- request = store[:audit_request]
93
- body =
94
- case
95
- when AUDIT_SNAPSHOT_MODES.include?(mode)
96
- ma_eliminate_not_changed_keys(initial_data, current_data)
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
- end
122
- rescue StandardError => e
123
- ModelsAuditor.log_error("Couldn't logged changes of #{self.class.name} id: #{self.try(:id)}")
124
- ModelsAuditor.log_error(e.message)
125
- ModelsAuditor.log_error(e.backtrace.take(100).join("\n"))
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.before_action :set_models_auditor_request_params
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.store[:audit_request] =
11
- ModelsAuditor::AuditRequest.new(
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
- rescue StandardError
16
- # ignored
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
@@ -1,3 +1,3 @@
1
1
  module ModelsAuditor
2
- VERSION = '1.1.1'
2
+ VERSION = '1.2.0'
3
3
  end
@@ -1,6 +1,7 @@
1
1
  require 'request_store'
2
2
  require 'models_auditor/engine'
3
3
  require 'models_auditor/config'
4
+ require 'models_auditor/default_formatter'
4
5
  require 'models_auditor/audit'
5
6
  require 'models_auditor/controller'
6
7
 
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.1.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-15 00:00:00.000000000 Z
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