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 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