models_auditor 0.1.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 +7 -0
- data/MIT-LICENSE +20 -0
- data/Rakefile +37 -0
- data/app/assets/javascripts/models_auditor/application.js +13 -0
- data/app/assets/stylesheets/models_auditor/application.css +64 -0
- data/app/controllers/models_auditor/audit_base_controller.rb +5 -0
- data/app/controllers/models_auditor/audit_controller.rb +121 -0
- data/app/helpers/models_auditor/application_helper.rb +4 -0
- data/app/models/models_auditor/audit_record.rb +17 -0
- data/app/models/models_auditor/audit_request.rb +12 -0
- data/app/views/layouts/models_auditor/application.html.erb +12 -0
- data/app/views/models_auditor/audit/_record.html.erb +39 -0
- data/app/views/models_auditor/audit/_request.html.erb +25 -0
- data/app/views/models_auditor/audit/index.html.erb +3 -0
- data/config/config_option_descriptions.yml +23 -0
- data/config/routes.rb +5 -0
- data/lib/generators/models_auditor/db_config/USAGE +7 -0
- data/lib/generators/models_auditor/db_config/db_config_generator.rb +23 -0
- data/lib/generators/models_auditor/install/USAGE +8 -0
- data/lib/generators/models_auditor/install/install_generator.rb +25 -0
- data/lib/generators/models_auditor/install/templates/initializer.rb.erb +13 -0
- data/lib/generators/models_auditor/migrations/USAGE +8 -0
- data/lib/generators/models_auditor/migrations/migrations_generator.rb +15 -0
- data/lib/generators/models_auditor/migrations/templates/create_audit_records.rb.erb +18 -0
- data/lib/generators/models_auditor/migrations/templates/create_audit_requests.rb.erb +12 -0
- data/lib/generators/models_auditor/migrations_helper.rb +24 -0
- data/lib/models_auditor.rb +37 -0
- data/lib/models_auditor/audit.rb +202 -0
- data/lib/models_auditor/config.rb +118 -0
- data/lib/models_auditor/controller.rb +67 -0
- data/lib/models_auditor/engine.rb +5 -0
- data/lib/models_auditor/version.rb +3 -0
- data/lib/tasks/models_auditor_tasks.rake +75 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/bin/setup +29 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +26 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +41 -0
- data/test/dummy/config/environments/production.rb +79 -0
- data/test/dummy/config/environments/test.rb +42 -0
- data/test/dummy/config/initializers/assets.rb +11 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +4 -0
- data/test/dummy/config/secrets.yml +22 -0
- data/test/dummy/public/404.html +67 -0
- data/test/dummy/public/422.html +67 -0
- data/test/dummy/public/500.html +66 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/integration/navigation_test.rb +8 -0
- data/test/models_auditor_test.rb +7 -0
- data/test/test_helper.rb +21 -0
- metadata +249 -0
@@ -0,0 +1,23 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
module ModelsAuditor
|
3
|
+
class DbConfigGenerator < Rails::Generators::Base
|
4
|
+
def add_db_config
|
5
|
+
if (nmsps = ModelsAuditor.config.connection_namespace).present?
|
6
|
+
inject_into_file 'config/database.yml', before: /\z/ do
|
7
|
+
"\n#{nmsps}_development: &#{nmsps}_development\n" +
|
8
|
+
" adapter: postgresql\n" +
|
9
|
+
" encoding: unicode\n" +
|
10
|
+
" database: audit_database\n" +
|
11
|
+
" pool: 5\n" +
|
12
|
+
" host: localhost\n" +
|
13
|
+
" username: audit_user\n" +
|
14
|
+
" password: \n" +
|
15
|
+
"#{nmsps}_production: *#{nmsps}_development\n" +
|
16
|
+
"#{nmsps}_staging: *#{nmsps}_development\n" +
|
17
|
+
"#{nmsps}_test: *#{nmsps}_development\n"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
module ModelsAuditor
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
4
|
+
source_root File.expand_path('../templates', __FILE__)
|
5
|
+
|
6
|
+
def descriptions
|
7
|
+
@descriptions ||= YAML.load_file(File.expand_path('../../../../../config/config_option_descriptions.yml', __FILE__))
|
8
|
+
end
|
9
|
+
|
10
|
+
def copy_initializer
|
11
|
+
template 'initializer.rb.erb', 'config/initializers/models_auditor.rb'
|
12
|
+
end
|
13
|
+
|
14
|
+
# def mount_routes
|
15
|
+
# [
|
16
|
+
# 'Rails.application.routes.draw do',
|
17
|
+
# 'Application.routes.draw do'
|
18
|
+
# ].each do |after_str|
|
19
|
+
# inject_into_file 'config/routes.rb', :after => after_str do
|
20
|
+
# "\n mount GlobalStore::Engine, at: '/global_store'\n"
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
# end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# Настройки аудитора моделей
|
2
|
+
|
3
|
+
ModelsAuditor.configure do |config|
|
4
|
+
<%
|
5
|
+
(ModelsAuditor::Config::CONFIG_OPTIONS).each do |option_sym|
|
6
|
+
descr = descriptions[option_sym.to_s].try(:split, "\n").try(:join, "\n # ")
|
7
|
+
concat " # #{descr.force_encoding('ASCII-8BIT')}\n" if descr.present?
|
8
|
+
concat " # config.#{option_sym} = "
|
9
|
+
concat (ModelsAuditor.config.default[option_sym].try(:[], :config) || 'nil').force_encoding('ASCII-8BIT')
|
10
|
+
concat "\n\n"
|
11
|
+
end
|
12
|
+
%>
|
13
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rails/generators/base'
|
2
|
+
require 'generators/models_auditor/migrations_helper'
|
3
|
+
|
4
|
+
module ModelsAuditor
|
5
|
+
class MigrationsGenerator < Rails::Generators::Base
|
6
|
+
include MigrationsHelper
|
7
|
+
source_root File.expand_path('../templates', __FILE__)
|
8
|
+
|
9
|
+
def create_migration_file
|
10
|
+
@migration_postfix = SecureRandom.hex
|
11
|
+
copy_migration 'create_audit_records', "create_audit_records_n#{@migration_postfix}"
|
12
|
+
copy_migration 'create_audit_requests', "create_audit_requests_n#{@migration_postfix}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class CreateAuditRecordsN<%= @migration_postfix %> < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
<% audit_tbn = ModelsAuditor.config.audit_records_table_name %>
|
4
|
+
create_table :<%= audit_tbn %>, comment: 'Журнал изменений данных в моделях' do |t|
|
5
|
+
t.integer :request_id, null: true, unsigned: true, comment: 'зафиксированные изменения'
|
6
|
+
t.integer :action, null: false, unsigned: true, comment: 'действие'
|
7
|
+
t.json :content, null: false, default: {}, comment: 'зафиксированные изменения'
|
8
|
+
t.string :object_type, null: false, comment: 'класс логируемого объекта'
|
9
|
+
t.integer :object_id, null: false, unsigned: true, comment: 'id логируемого объекта'
|
10
|
+
t.json :bridge, null: true, comment: 'данные внешних ключей связующей таблицы'
|
11
|
+
t.datetime :created_at, null: false, comment: 'дата и время зафиксированных изменений'
|
12
|
+
end
|
13
|
+
add_index :<%= audit_tbn %>, :id
|
14
|
+
add_index :<%= audit_tbn %>, :request_id
|
15
|
+
add_index :<%= audit_tbn %>, :created_at
|
16
|
+
add_index :<%= audit_tbn %>, [:object_id, :object_type]
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class CreateAuditRequestsN<%= @migration_postfix %> < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
<% audit_tbn = ModelsAuditor.config.audit_requests_table_name %>
|
4
|
+
create_table :<%= audit_tbn %>, comment: 'Журнал изменений данных в моделях' do |t|
|
5
|
+
t.integer :user_id, null: true, unsigned: true, comment: 'id ответственного'
|
6
|
+
t.json :request_info, null: false, default: {}, comment: 'Информация о запросе'
|
7
|
+
t.datetime :created_at, null: false, comment: 'дата и время запроса'
|
8
|
+
end
|
9
|
+
add_index :<%= audit_tbn %>, :id
|
10
|
+
add_index :<%= audit_tbn %>, :created_at
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module ModelsAuditor
|
2
|
+
module MigrationsHelper
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
include Rails::Generators::Migration
|
7
|
+
|
8
|
+
def self.next_migration_number(dirname)
|
9
|
+
next_migration_number = current_migration_number(dirname) + 1
|
10
|
+
ActiveRecord::Migration.next_migration_number(next_migration_number)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def copy_migration(filename, destination)
|
15
|
+
migrations_dir = File.join('db', ModelsAuditor.config.audit_migrations_dir)
|
16
|
+
|
17
|
+
if self.class.migration_exists?(migrations_dir, "#{destination}.rb")
|
18
|
+
say_status('skipped', "Migration #{destination}.rb already exists in #{migrations_dir}")
|
19
|
+
else
|
20
|
+
migration_template "#{filename}.rb.erb", File.join(migrations_dir, "#{destination}.rb")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'request_store'
|
2
|
+
require 'models_auditor/engine'
|
3
|
+
require 'models_auditor/config'
|
4
|
+
require 'models_auditor/audit'
|
5
|
+
require 'models_auditor/controller'
|
6
|
+
|
7
|
+
module ModelsAuditor
|
8
|
+
module_function
|
9
|
+
def log_error(*args)
|
10
|
+
if (logger = ModelsAuditor.config.logger)
|
11
|
+
logger.error(*args)
|
12
|
+
end
|
13
|
+
puts *args
|
14
|
+
end
|
15
|
+
|
16
|
+
def log_info(*args)
|
17
|
+
if (logger = ModelsAuditor.config.logger)
|
18
|
+
logger.info(*args)
|
19
|
+
end
|
20
|
+
puts *args
|
21
|
+
end
|
22
|
+
|
23
|
+
def log_warn(*args)
|
24
|
+
if (logger = ModelsAuditor.config.logger)
|
25
|
+
logger.warn(*args)
|
26
|
+
end
|
27
|
+
puts *args
|
28
|
+
end
|
29
|
+
|
30
|
+
def store
|
31
|
+
RequestStore.store[:models_auditor_store] ||= {}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
ActiveSupport.on_load(:active_record) do
|
36
|
+
include ModelsAuditor::Audit
|
37
|
+
end
|
@@ -0,0 +1,202 @@
|
|
1
|
+
module ModelsAuditor
|
2
|
+
module Audit
|
3
|
+
# Сбор данных через метод #as_json
|
4
|
+
# @example enable_audit ModelsAuditor::Audit::AUDIT_MODE_JSON, only: [:title, :subtitle, :published_at]
|
5
|
+
AUDIT_MODE_JSON = 1
|
6
|
+
# Сбор данных через сериалайзер
|
7
|
+
# @example enable_audit ModelsAuditor::Audit::AUDIT_MODE_SERIALIZER, serializer: AuditPostSerializer
|
8
|
+
AUDIT_MODE_SERIALIZER = 2
|
9
|
+
# Сбор данных через назначенный метод
|
10
|
+
# @example enable_audit ModelsAuditor::Audit::AUDIT_MODE_SERIALIZER, method: :logged_data
|
11
|
+
AUDIT_MODE_METHOD = 3
|
12
|
+
# Сбор данных через #previous_changes
|
13
|
+
# @example enable_audit ModelsAuditor::Audit::AUDIT_MODE_CHANGES_ONLY
|
14
|
+
AUDIT_MODE_CHANGES_ONLY = 4
|
15
|
+
|
16
|
+
AUDIT_SNAPSHOT_MODES = [AUDIT_MODE_JSON, AUDIT_MODE_SERIALIZER, AUDIT_MODE_METHOD]
|
17
|
+
AUDIT_CHANGES_MODES = [AUDIT_MODE_CHANGES_ONLY]
|
18
|
+
|
19
|
+
def self.included(base)
|
20
|
+
base.send :extend, ClassMethods
|
21
|
+
end
|
22
|
+
|
23
|
+
module InstanceMethods
|
24
|
+
def do_audit_init_snapshot
|
25
|
+
return unless ModelsAuditor.config.audit_enabled
|
26
|
+
mode = self.class.instance_variable_get(:@audit_mode)
|
27
|
+
return unless self.class.instance_variable_get(:@audit_enabled) && AUDIT_SNAPSHOT_MODES.include?(mode)
|
28
|
+
ma_store_initial_state(ModelsAuditor.store)
|
29
|
+
end
|
30
|
+
|
31
|
+
def do_audit_process
|
32
|
+
return unless ModelsAuditor.config.audit_enabled
|
33
|
+
return unless self.class.instance_variable_get(:@audit_enabled)
|
34
|
+
mode = self.class.instance_variable_get(:@audit_mode)
|
35
|
+
options = self.class.instance_variable_get(:@audit_settings) || {}
|
36
|
+
store = ModelsAuditor.store
|
37
|
+
|
38
|
+
initial_data = ma_get_initial_state(store)
|
39
|
+
current_data = ma_auditor_get_data
|
40
|
+
|
41
|
+
action =
|
42
|
+
case
|
43
|
+
when transaction_include_any_action?([:create])
|
44
|
+
ModelsAuditor::AuditRecord::ACTION_CREATE
|
45
|
+
when transaction_include_any_action?([:update])
|
46
|
+
ModelsAuditor::AuditRecord::ACTION_UPDATE
|
47
|
+
when transaction_include_any_action?([:destroy])
|
48
|
+
ModelsAuditor::AuditRecord::ACTION_DESTROY
|
49
|
+
end
|
50
|
+
|
51
|
+
bridge =
|
52
|
+
if options[:bridge]
|
53
|
+
options[:bridge].each_with_object({}) { |(model_name, key), o| o[model_name] = {key => __send__(key)} }
|
54
|
+
end
|
55
|
+
|
56
|
+
Thread.new do
|
57
|
+
begin
|
58
|
+
log_anyway = !ModelsAuditor.config.audit_request_changes_only
|
59
|
+
if (request = store[:audit_request]) || log_anyway
|
60
|
+
body =
|
61
|
+
case
|
62
|
+
when AUDIT_SNAPSHOT_MODES.include?(mode)
|
63
|
+
ma_eliminate_not_changed_keys(initial_data, current_data)
|
64
|
+
when AUDIT_CHANGES_MODES.include?(mode)
|
65
|
+
current_data
|
66
|
+
else
|
67
|
+
raise ArgumentError.new('Incorrect value of argument audit_type')
|
68
|
+
end
|
69
|
+
|
70
|
+
if request.try(:new_record?) && !request.save
|
71
|
+
ModelsAuditor.log_error("Couldn't save request record")
|
72
|
+
ModelsAuditor.log_error(request.errors.full_messages)
|
73
|
+
return
|
74
|
+
end
|
75
|
+
record =
|
76
|
+
ModelsAuditor::AuditRecord.new(
|
77
|
+
request: request,
|
78
|
+
auditable: self,
|
79
|
+
content: body,
|
80
|
+
action: action,
|
81
|
+
bridge: bridge
|
82
|
+
)
|
83
|
+
unless record.save
|
84
|
+
ModelsAuditor.log_error("Couldn't logged changes of #{self.class.name} id: #{self.try(:id)}")
|
85
|
+
ModelsAuditor.log_error(record.errors.full_messages)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
rescue Exception => e
|
89
|
+
ModelsAuditor.log_error("Couldn't logged changes of #{self.class.name} id: #{self.try(:id)}")
|
90
|
+
ModelsAuditor.log_error(e.message)
|
91
|
+
ModelsAuditor.log_error(e.backtrace.take(100).join("\n"))
|
92
|
+
end
|
93
|
+
# TODO To remove the #join call from the thread block after debugging
|
94
|
+
end.join
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
# Сравнивает два хэша, оставляя только отличающиеся по значению ключи
|
100
|
+
# @return [Hash] filtered result with different attributes only
|
101
|
+
def ma_eliminate_not_changed_keys(old_hash, new_hash)
|
102
|
+
case
|
103
|
+
# Равны или оба nil
|
104
|
+
when old_hash == new_hash
|
105
|
+
{}
|
106
|
+
# Один из них nil
|
107
|
+
when (old_hash && new_hash).nil?
|
108
|
+
(old_hash || new_hash).keys.each_with_object({}) do |key, o|
|
109
|
+
if (was = old_hash.try(:[], key)) != (now = new_hash.try(:[], key))
|
110
|
+
o[key] = [was, now]
|
111
|
+
end
|
112
|
+
end
|
113
|
+
else # Оба не nil
|
114
|
+
(old_hash.keys | new_hash.keys).each_with_object({}) do |key, o|
|
115
|
+
if (was = old_hash[key]) != (now = new_hash[key])
|
116
|
+
o[key] = [was, now]
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# Запоминает сериализованные данные для аудита
|
123
|
+
# Вызывать данный метод следует в коллбэке after_initialize
|
124
|
+
# Или в любом другом месте до изменения значений аттрибутов
|
125
|
+
def ma_store_initial_state(store)
|
126
|
+
store[:initial_states] ||= {}
|
127
|
+
states_of_mclass = (store[:initial_states][self.class.name] ||= {})
|
128
|
+
states_of_mclass[self.id] ||= ma_auditor_get_data
|
129
|
+
end
|
130
|
+
|
131
|
+
# Получает сериализованные данные для аудита подготовленные при инициализации сущности
|
132
|
+
# @return [Hash|nil] Начальные данные
|
133
|
+
def ma_get_initial_state(store)
|
134
|
+
store[:initial_states].try(:[], self.class.name).try(:[], self.id)
|
135
|
+
end
|
136
|
+
|
137
|
+
# Получает сериализованные данные для аудита
|
138
|
+
def ma_auditor_get_data
|
139
|
+
options = self.class.instance_variable_get(:@audit_settings) || {}
|
140
|
+
audit_params = options[:params]
|
141
|
+
mode = self.class.instance_variable_get(:@audit_mode)
|
142
|
+
case mode
|
143
|
+
when AUDIT_MODE_JSON
|
144
|
+
self.as_json(audit_params)
|
145
|
+
when AUDIT_MODE_SERIALIZER
|
146
|
+
if (serializer = options[:serializer]).blank?
|
147
|
+
raise ArgumentError.new('Required option :serializer for AUDIT_MODE_SERIALIZER was not passed')
|
148
|
+
end
|
149
|
+
serializer.new(self, audit_params || {}).as_json
|
150
|
+
when AUDIT_MODE_METHOD
|
151
|
+
if (method = options[:serializer]).blank?
|
152
|
+
raise ArgumentError.new('Required option :method for AUDIT_MODE_METHOD was not passed')
|
153
|
+
end
|
154
|
+
unless self.respond_to?(method)
|
155
|
+
raise ArgumentError.new("Passed method '#{method}' is undefined")
|
156
|
+
end
|
157
|
+
self.__send__(method)
|
158
|
+
when AUDIT_MODE_CHANGES_ONLY
|
159
|
+
self.previous_changes
|
160
|
+
else
|
161
|
+
raise ArgumentError.new('Incorrect value of argument audit_type')
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
|
167
|
+
module ClassMethods
|
168
|
+
# Активирует аудит изменений данных модели
|
169
|
+
# @param [Integer] audit_mode Способ логирования
|
170
|
+
# возможные значения: AUDIT_MODE_JSON | AUDIT_MODE_SERIALIZER | AUDIT_MODE_METHOD | AUDIT_MODE_CHANGES_ONLY
|
171
|
+
# AUDIT_MODE_JSON - Сериализация путем вызова метода as_json
|
172
|
+
# AUDIT_MODE_SERIALIZER - Сериализация через использование сериалайзера, указанного в опции :serializer
|
173
|
+
# AUDIT_MODE_METHOD - Сериализация данных формируемых в методе, указанном в опции :method
|
174
|
+
# AUDIT_MODE_CHANGES_ONLY - Сериализация данных модели, которые были изменены
|
175
|
+
# @param [Hash] options Настройки логирования
|
176
|
+
# @option options [params] Параметры сериализации данных.
|
177
|
+
# Для AUDIT_MODE_JSON значение передается в метод #as_json
|
178
|
+
# @example enable_audit ModelsAuditor::Audit::AUDIT_MODE_JSON, only: [:title, :subtitle, :published_at]
|
179
|
+
# Для AUDIT_MODE_SERIALIZER значение передается в сериалайзер в качестве опций
|
180
|
+
# @example enable_audit ModelsAuditor::Audit::AUDIT_MODE_SERIALIZER, serializer: AuditPostSerializer
|
181
|
+
# Для AUDIT_MODE_METHOD значение игнорируется
|
182
|
+
# @example enable_audit ModelsAuditor::Audit::AUDIT_MODE_SERIALIZER, method: :logged_data
|
183
|
+
# Для AUDIT_MODE_CHANGES_ONLY значение игнорируется
|
184
|
+
# @example enable_audit ModelsAuditor::Audit::AUDIT_MODE_CHANGES_ONLY
|
185
|
+
def enable_audit(audit_mode, options = {})
|
186
|
+
@audit_enabled = true
|
187
|
+
@audit_mode = audit_mode
|
188
|
+
@audit_settings = options
|
189
|
+
# Lazily include the instance methods so we don't clutter up
|
190
|
+
# any more ActiveRecord models than we have to.
|
191
|
+
send :include, InstanceMethods
|
192
|
+
after_initialize :do_audit_init_snapshot
|
193
|
+
after_commit :do_audit_process
|
194
|
+
end
|
195
|
+
|
196
|
+
# Дезактивирует аудит изменений данных модели
|
197
|
+
def disable_audit
|
198
|
+
@audit_enabled = false
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
module ModelsAuditor
|
2
|
+
class Config
|
3
|
+
CONFIG_OPTIONS = %i(
|
4
|
+
audit_enabled
|
5
|
+
connection_namespace
|
6
|
+
audit_records_table_name
|
7
|
+
audit_requests_table_name
|
8
|
+
audit_migrations_dir
|
9
|
+
audit_request_changes_only
|
10
|
+
logger
|
11
|
+
records_per_page
|
12
|
+
fake_total_count
|
13
|
+
audit_controller_base
|
14
|
+
respond_to_json_enabled
|
15
|
+
respond_to_html_enabled
|
16
|
+
json_response_data_key
|
17
|
+
json_response_meta_key
|
18
|
+
)
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
@indexed_relations = []
|
22
|
+
end
|
23
|
+
|
24
|
+
def default
|
25
|
+
@default ||= {
|
26
|
+
audit_enabled: {
|
27
|
+
config: 'true',
|
28
|
+
val: true
|
29
|
+
},
|
30
|
+
connection_namespace: {
|
31
|
+
config: "'audit'",
|
32
|
+
val: 'audit'
|
33
|
+
},
|
34
|
+
audit_records_table_name: {
|
35
|
+
config: "'audit_records'",
|
36
|
+
val: 'audit_records'
|
37
|
+
},
|
38
|
+
audit_requests_table_name: {
|
39
|
+
config: "'audit_requests'",
|
40
|
+
val: 'audit_requests'
|
41
|
+
},
|
42
|
+
audit_migrations_dir: {
|
43
|
+
config: "'audit_migrate'",
|
44
|
+
val: 'audit_migrate'
|
45
|
+
},
|
46
|
+
logger: {
|
47
|
+
config: "Logger.new(Rails.root.join('log', 'models_auditor.log'))",
|
48
|
+
val: Logger.new(Rails.root.join('log', 'models_auditor.log'))
|
49
|
+
},
|
50
|
+
audit_request_changes_only: {
|
51
|
+
config: 'true',
|
52
|
+
val: true
|
53
|
+
},
|
54
|
+
records_per_page: {
|
55
|
+
config: '10',
|
56
|
+
val: 10
|
57
|
+
},
|
58
|
+
fake_total_count: {
|
59
|
+
config: 'true',
|
60
|
+
val: true
|
61
|
+
},
|
62
|
+
audit_controller_base: {
|
63
|
+
config: "'ModelsAuditor::AuditBaseController'",
|
64
|
+
val: 'ModelsAuditor::AuditBaseController'
|
65
|
+
},
|
66
|
+
respond_to_json_enabled: {
|
67
|
+
config: 'true',
|
68
|
+
val: true
|
69
|
+
},
|
70
|
+
respond_to_html_enabled: {
|
71
|
+
config: 'false',
|
72
|
+
val: false
|
73
|
+
},
|
74
|
+
json_response_data_key: {
|
75
|
+
config: "'entries'",
|
76
|
+
val: 'entries'
|
77
|
+
},
|
78
|
+
json_response_meta_key: {
|
79
|
+
config: "'meta'",
|
80
|
+
val: 'meta'
|
81
|
+
},
|
82
|
+
}
|
83
|
+
end
|
84
|
+
|
85
|
+
def method_missing(method_sym, *args)
|
86
|
+
method_name = method_sym.to_s
|
87
|
+
option_name = method_name.tr('=', '')
|
88
|
+
super if CONFIG_OPTIONS.exclude?(option_name.to_sym)
|
89
|
+
if method_name =~ /^.*=$/
|
90
|
+
raise ArgumentError.new('Incorrect number of arguments') if args.size != 1
|
91
|
+
instance_variable_set("@#{option_name}", args[0]) unless ModelsAuditor.configured?
|
92
|
+
else
|
93
|
+
var_name = "@#{option_name}"
|
94
|
+
instance_variable_defined?(var_name) ?
|
95
|
+
instance_variable_get(var_name) :
|
96
|
+
default[option_name.to_sym].try(:[], :val)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
module_function
|
103
|
+
|
104
|
+
def configure(&block)
|
105
|
+
Rails.application.config.after_initialize do
|
106
|
+
block.call(config)
|
107
|
+
@configured = true
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def configured?
|
112
|
+
@configured
|
113
|
+
end
|
114
|
+
|
115
|
+
def config
|
116
|
+
@config ||= Config.new
|
117
|
+
end
|
118
|
+
end
|