mongoid-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/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/LICENSE.txt +21 -0
- data/README.md +272 -0
- data/Rakefile +12 -0
- data/lib/mongoid/auditor/audit.rb +52 -0
- data/lib/mongoid/auditor/configuration.rb +27 -0
- data/lib/mongoid/auditor/generators/install_generator.rb +18 -0
- data/lib/mongoid/auditor/generators/templates/mongoid_auditor_initializer.rb +12 -0
- data/lib/mongoid/auditor/helpers/controller_helpers/audit_controller_error_log.rb +75 -0
- data/lib/mongoid/auditor/helpers/controller_helpers/controller_audit_helper.rb +22 -0
- data/lib/mongoid/auditor/helpers/controller_helpers/init_audit_log.rb +35 -0
- data/lib/mongoid/auditor/helpers/jobs/auditor_job.rb +56 -0
- data/lib/mongoid/auditor/helpers/jobs/concerns/auditable_job_error.rb +58 -0
- data/lib/mongoid/auditor/helpers/jobs/concerns/init_job_audit_log.rb +68 -0
- data/lib/mongoid/auditor/helpers/models/audit_log.rb +64 -0
- data/lib/mongoid/auditor/helpers/models/concerns/audit_log_helpers.rb +68 -0
- data/lib/mongoid/auditor/helpers/models/concerns/auditable.rb +89 -0
- data/lib/mongoid/auditor/helpers/models/concerns/model_logs_helper.rb +53 -0
- data/lib/mongoid/auditor/helpers/models/current.rb +10 -0
- data/lib/mongoid/auditor/helpers/models/request_context.rb +19 -0
- data/lib/mongoid/auditor/railtie.rb +34 -0
- data/lib/mongoid/auditor/version.rb +7 -0
- data/lib/mongoid/auditor.rb +21 -0
- data/sig/mongoid/auditor.rbs +6 -0
- metadata +115 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mongoid
|
|
4
|
+
module Auditor
|
|
5
|
+
module InitAuditLog
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
MUTATION_METHODS = %w[POST PUT PATCH DELETE].freeze
|
|
9
|
+
included do
|
|
10
|
+
prepend_before_action :init_audit_store, if: -> { MUTATION_METHODS.include?(request.method) }
|
|
11
|
+
include ControllerAuditHelper
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def init_audit_store
|
|
15
|
+
return unless ::Mongoid::Auditor.config.enabled && ::Mongoid::Auditor.config.log_models
|
|
16
|
+
|
|
17
|
+
set_current(:request_id, request.request_id)
|
|
18
|
+
set_current(:actor_id, current_user&.id&.to_s)
|
|
19
|
+
set_current(:path, "#{request.method} #{request.fullpath}")
|
|
20
|
+
set_current(:request_params, filter_sensitive_params(request.filtered_parameters))
|
|
21
|
+
set_current(:audit_logs, [])
|
|
22
|
+
set_current(:audit_sequence, 0)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def filter_sensitive_params(params)
|
|
26
|
+
skip_fields = ::Mongoid::Auditor.config.skip_password_fields || []
|
|
27
|
+
params.except(*skip_fields)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def set_current(key, value)
|
|
31
|
+
Mongoid::Auditor::Current.send("#{key}=", value)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mongoid
|
|
4
|
+
module Auditor
|
|
5
|
+
class AuditorJob < ActiveJob::Base
|
|
6
|
+
class_attribute :skip_audit, default: false
|
|
7
|
+
|
|
8
|
+
self.skip_audit = true
|
|
9
|
+
|
|
10
|
+
queue_as :default
|
|
11
|
+
|
|
12
|
+
def perform(state, exception = nil, entry = nil)
|
|
13
|
+
return unless config.enabled
|
|
14
|
+
|
|
15
|
+
case state.to_sym
|
|
16
|
+
when :model
|
|
17
|
+
log_model(entry)
|
|
18
|
+
when :controller
|
|
19
|
+
log_controller_error(exception, entry)
|
|
20
|
+
else
|
|
21
|
+
log_unknown_state(state)
|
|
22
|
+
end
|
|
23
|
+
rescue StandardError => e
|
|
24
|
+
log_failure(e)
|
|
25
|
+
raise
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def config
|
|
31
|
+
::Mongoid::Auditor.config
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def log_model(entry)
|
|
35
|
+
Audit.log(entry) if config.log_models
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def log_controller_error(exception, entry)
|
|
39
|
+
return unless config.log_controllers
|
|
40
|
+
|
|
41
|
+
Audit.send(:log_error, exception, entry)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def log_unknown_state(state)
|
|
45
|
+
logger&.error("AuditorJob unknown state: #{state}")
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def log_failure(error)
|
|
49
|
+
logger&.error(
|
|
50
|
+
"AuditorJob failed: #{error.class} #{error.message}\n" \
|
|
51
|
+
"#{error.backtrace&.take(5)&.join("\n")}"
|
|
52
|
+
)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mongoid
|
|
4
|
+
module Auditor
|
|
5
|
+
module AuditableJobError
|
|
6
|
+
def audit_job_exceptions(job)
|
|
7
|
+
@current_job = job
|
|
8
|
+
yield
|
|
9
|
+
rescue StandardError => e
|
|
10
|
+
audit_job_error(e)
|
|
11
|
+
raise
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
def audit_job_error(exception)
|
|
17
|
+
return unless ::Mongoid::Auditor.config.enabled
|
|
18
|
+
|
|
19
|
+
data = build_job_entry(exception)
|
|
20
|
+
::Mongoid::Auditor::AuditorJob.perform_later(:controller, data[:error], data[:entry])
|
|
21
|
+
rescue StandardError => e
|
|
22
|
+
Rails.logger&.error("AuditableJobError failed: #{e.class} #{e.message}\n#{e.backtrace&.take(5)&.join("\n")}")
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def build_job_entry(exception)
|
|
26
|
+
request_id = set_request_id
|
|
27
|
+
actor = 'BackgroundJobError'
|
|
28
|
+
|
|
29
|
+
{
|
|
30
|
+
entry: {
|
|
31
|
+
request_id: request_id,
|
|
32
|
+
actor: actor,
|
|
33
|
+
path: "Job #{@current_job.class.name}",
|
|
34
|
+
params: @current_job.arguments,
|
|
35
|
+
model_type: @current_job.class.name,
|
|
36
|
+
model_id: nil,
|
|
37
|
+
has_error: true,
|
|
38
|
+
event: 'perform',
|
|
39
|
+
dirties: {},
|
|
40
|
+
sequence: ::Mongoid::Auditor::Current.audit_sequence.to_i + 1
|
|
41
|
+
},
|
|
42
|
+
error: {
|
|
43
|
+
class: exception.class.to_s,
|
|
44
|
+
message: exception.message,
|
|
45
|
+
backtrace: exception.backtrace&.take(5)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def set_request_id
|
|
51
|
+
return unless @current_job
|
|
52
|
+
|
|
53
|
+
context = ::Mongoid::Auditor::RequestContext.find_by(job_id: @current_job.job_id)
|
|
54
|
+
context&.request_id || "#{@current_job.class.name}-#{@current_job.job_id}"
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mongoid
|
|
4
|
+
module Auditor
|
|
5
|
+
module InitJobAuditLog
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
included do
|
|
9
|
+
include AuditableJobError
|
|
10
|
+
|
|
11
|
+
before_enqueue do |job|
|
|
12
|
+
store_request_context(job)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
before_perform do |job|
|
|
16
|
+
::Mongoid::Auditor::Current.reset_all
|
|
17
|
+
|
|
18
|
+
request_id_from_context(job)
|
|
19
|
+
init_job_audit_store(job) unless job.class.skip_audit
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
around_perform do |job, block|
|
|
23
|
+
audit_job_exceptions(job, &block)
|
|
24
|
+
clear_request_context(job)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def store_request_context(job)
|
|
31
|
+
return if job.class.skip_audit
|
|
32
|
+
|
|
33
|
+
request_id = ::Mongoid::Auditor::Current.request_id
|
|
34
|
+
::Mongoid::Auditor::RequestContext.create!(job_id: job.job_id, request_id: request_id)
|
|
35
|
+
rescue StandardError => e
|
|
36
|
+
Rails.logger&.error("Failed to store request context: #{e.class} #{e.message}")
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def request_id_from_context(job)
|
|
40
|
+
context = ::Mongoid::Auditor::RequestContext.find_by(job_id: job.job_id)
|
|
41
|
+
::Mongoid::Auditor::Current.request_id = context&.request_id
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def init_job_audit_store(job)
|
|
45
|
+
set_current(:request_id, ::Mongoid::Auditor::Current.request_id || "Job #{job.class.name}-#{job.job_id}")
|
|
46
|
+
set_current(:actor_id, 'Background Job')
|
|
47
|
+
|
|
48
|
+
set_current(:path, "Job #{job.class.name}")
|
|
49
|
+
set_current(:request_params, job.arguments || [])
|
|
50
|
+
|
|
51
|
+
set_current(:audit_logs, [])
|
|
52
|
+
set_current(:audit_sequence, 0)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def set_current(key, value)
|
|
56
|
+
::Mongoid::Auditor::Current.public_send("#{key}=", value)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def clear_request_context(job)
|
|
60
|
+
return if job.nil?
|
|
61
|
+
|
|
62
|
+
::Mongoid::Auditor::RequestContext.where(job_id: job.job_id).delete_all
|
|
63
|
+
rescue StandardError => e
|
|
64
|
+
Rails.logger&.error("Failed to clear request context: #{e.class} #{e.message}")
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mongoid
|
|
4
|
+
module Auditor
|
|
5
|
+
class AuditLog
|
|
6
|
+
include Mongoid::Document
|
|
7
|
+
include Mongoid::Timestamps
|
|
8
|
+
include Mongoid::Auditor::AuditLogHelpers
|
|
9
|
+
|
|
10
|
+
field :request_id, type: String
|
|
11
|
+
field :actor, type: String
|
|
12
|
+
|
|
13
|
+
field :path, type: String
|
|
14
|
+
field :params, type: Hash, default: {}
|
|
15
|
+
|
|
16
|
+
field :model_type, type: String
|
|
17
|
+
field :model_id, type: String
|
|
18
|
+
field :has_error, type: Boolean, default: false
|
|
19
|
+
field :event, type: String
|
|
20
|
+
field :dirties, type: Hash, default: {}
|
|
21
|
+
|
|
22
|
+
# optional ordering/consistency helpers
|
|
23
|
+
field :sequence, type: Integer
|
|
24
|
+
|
|
25
|
+
field :error, type: Hash, default: nil
|
|
26
|
+
field :model_error, type: Hash, default: nil
|
|
27
|
+
|
|
28
|
+
# Indexes for performance
|
|
29
|
+
index({ request_id: 1 })
|
|
30
|
+
index({ model_type: 1, model_id: 1 })
|
|
31
|
+
index({ model_type: 1, model_id: 1, event: 1 })
|
|
32
|
+
index({ actor: 1 })
|
|
33
|
+
index({ has_error: 1, created_at: -1 })
|
|
34
|
+
index({ created_at: -1 })
|
|
35
|
+
index({ request_id: 1, sequence: 1 })
|
|
36
|
+
|
|
37
|
+
# Validations
|
|
38
|
+
validates :request_id, presence: true
|
|
39
|
+
validates :event, presence: true, inclusion: { in: %w[create update destroy error] }
|
|
40
|
+
validates :sequence, presence: true, numericality: { only_integer: true }
|
|
41
|
+
|
|
42
|
+
def model
|
|
43
|
+
return if model_type.blank? || model_id.blank?
|
|
44
|
+
|
|
45
|
+
model_type.constantize.find(model_id)
|
|
46
|
+
rescue StandardError
|
|
47
|
+
nil
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Prevent destructive operations in production - don't allow erasing audit history
|
|
51
|
+
if defined?(Rails) && Rails.env.production?
|
|
52
|
+
%w[destroy destroy! delete delete!].each do |method_name|
|
|
53
|
+
define_method(method_name) do
|
|
54
|
+
raise 'AuditLog is immutable in production. You cannot rewrite history!'
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def self.delete_all(*)
|
|
59
|
+
raise 'AuditLog is immutable in production. You cannot rewrite history!'
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mongoid
|
|
4
|
+
module Auditor
|
|
5
|
+
module AuditLogHelpers
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
included do
|
|
9
|
+
# Ensure we're using the namespaced AuditLog
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class_methods do
|
|
13
|
+
# All audit logs that represent errors
|
|
14
|
+
def errors
|
|
15
|
+
where(has_error: true)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def record_logs(request_id)
|
|
19
|
+
where(request_id: request_id)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def created_errors_today
|
|
23
|
+
event_errors('create')
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def updated_errors_today
|
|
27
|
+
event_errors('update')
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def deleted_errors_today
|
|
31
|
+
event_errors('destroy')
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def event_errors(event)
|
|
35
|
+
where(created_at: Time.current.all_day, has_error: true, event: event)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Errors created today
|
|
39
|
+
def errors_today
|
|
40
|
+
errors.where(created_at: Time.current.all_day)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Errors created in last N days
|
|
44
|
+
def errors_last(days)
|
|
45
|
+
errors.where(:created_at.gte => days.days.ago)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Errors by specific actor
|
|
49
|
+
def errors_by(actor_id)
|
|
50
|
+
errors.where(actor: actor_id)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Quick summary: class names and counts
|
|
54
|
+
def error_summary
|
|
55
|
+
errors.group_by { |log| log.error&.dig('class') || 'Unknown' }.transform_values(&:count)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def error_summary_today
|
|
59
|
+
errors_today.group_by { |log| log.error&.dig('class') || 'Unknown' }.transform_values(&:count)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def error_summary_last(days)
|
|
63
|
+
errors_last(days).group_by { |log| log.error&.dig('class') || 'Unknown' }.transform_values(&:count)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mongoid
|
|
4
|
+
module Auditor
|
|
5
|
+
module Auditable
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
included do
|
|
9
|
+
include Mongoid::Auditor::ModelLogsHelper
|
|
10
|
+
|
|
11
|
+
after_create :audit_create
|
|
12
|
+
after_update :audit_update
|
|
13
|
+
before_destroy :audit_destroy
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
MODEL_AUDIT = :model
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def audit_create
|
|
21
|
+
before_attrs = {}
|
|
22
|
+
after_attrs = attributes.deep_stringify_keys
|
|
23
|
+
append_audit_entry('create', before_attrs, after_attrs)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def audit_update
|
|
27
|
+
return if previous_changes.blank?
|
|
28
|
+
|
|
29
|
+
before_attrs = previous_changes.transform_values(&:first).deep_stringify_keys
|
|
30
|
+
after_attrs = previous_changes.transform_values(&:last).deep_stringify_keys
|
|
31
|
+
append_audit_entry('update', before_attrs, after_attrs)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def audit_destroy
|
|
35
|
+
before_attrs = attributes.deep_stringify_keys
|
|
36
|
+
after_attrs = nil
|
|
37
|
+
append_audit_entry('destroy', before_attrs, after_attrs)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def append_audit_entry(event, before_attrs, after_attrs)
|
|
41
|
+
return unless ::Mongoid::Auditor.config.enabled && ::Mongoid::Auditor.config.log_models
|
|
42
|
+
return if ::Mongoid::Auditor::Current.path.nil?
|
|
43
|
+
|
|
44
|
+
entry = build_entry(event, before_attrs, after_attrs)
|
|
45
|
+
::Mongoid::Auditor::AuditorJob.perform_later(MODEL_AUDIT, nil, entry)
|
|
46
|
+
rescue StandardError => e
|
|
47
|
+
logger&.error("Auditable#append_audit_entry failed for #{self.class.name}(#{id}): #{e.class} #{e.message}")
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def logger
|
|
51
|
+
defined?(Rails) ? Rails.logger : nil
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def build_entry(event, before_attrs, after_attrs)
|
|
55
|
+
::Mongoid::Auditor::Current.audit_sequence ||= 0
|
|
56
|
+
seq = ::Mongoid::Auditor::Current.audit_sequence + 1
|
|
57
|
+
::Mongoid::Auditor::Current.audit_sequence = seq
|
|
58
|
+
|
|
59
|
+
# Transform before/after attrs into { attribute: [before_value, after_value] } format
|
|
60
|
+
dirties = build_dirties_hash(before_attrs, after_attrs)
|
|
61
|
+
|
|
62
|
+
{
|
|
63
|
+
request_id: ::Mongoid::Auditor::Current.request_id,
|
|
64
|
+
actor: ::Mongoid::Auditor::Current.actor_id,
|
|
65
|
+
path: ::Mongoid::Auditor::Current.path,
|
|
66
|
+
params: ::Mongoid::Auditor::Current.request_params,
|
|
67
|
+
model_type: self.class.name,
|
|
68
|
+
model_id: id.to_s,
|
|
69
|
+
event: event,
|
|
70
|
+
dirties: dirties,
|
|
71
|
+
sequence: seq
|
|
72
|
+
}
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def build_dirties_hash(before_attrs, after_attrs)
|
|
76
|
+
before_attrs ||= {}
|
|
77
|
+
after_attrs ||= {}
|
|
78
|
+
|
|
79
|
+
all_keys = (before_attrs.keys + after_attrs.keys).uniq
|
|
80
|
+
|
|
81
|
+
all_keys.each_with_object({}) do |key, result|
|
|
82
|
+
before_value = before_attrs[key]
|
|
83
|
+
after_value = after_attrs[key]
|
|
84
|
+
result[key] = [before_value, after_value]
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mongoid
|
|
4
|
+
module Auditor
|
|
5
|
+
module ModelLogsHelper
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
def logs
|
|
9
|
+
::Mongoid::Auditor::AuditLog.where(model_id: id.to_s, model_type: self.class.name)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def create_errors_today
|
|
13
|
+
error_events('create')
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def update_errors_today
|
|
17
|
+
error_events('update')
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def destroy_errors_today
|
|
21
|
+
error_events('destroy')
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def created_today
|
|
25
|
+
audit_events('create')
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def updated_today
|
|
29
|
+
audit_events('update')
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def deleted_today
|
|
33
|
+
audit_events('destroy')
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def error_events(event)
|
|
37
|
+
::Mongoid::Auditor::AuditLog.where(model_type: self.class.name, has_error: true, event: event, created_at: today_time)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def audit_events(event)
|
|
41
|
+
::Mongoid::Auditor::AuditLog.where(model_type: self.class.name, event: event, created_at: today_time)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def error
|
|
45
|
+
::Mongoid::Auditor::AuditLog.where(model_id: id.to_s, model_type: self.class.name, has_error: true)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def today_time
|
|
49
|
+
@today_time ||= Time.current.all_day
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mongoid
|
|
4
|
+
module Auditor
|
|
5
|
+
class RequestContext
|
|
6
|
+
include Mongoid::Document
|
|
7
|
+
include Mongoid::Timestamps
|
|
8
|
+
|
|
9
|
+
field :job_id, type: String
|
|
10
|
+
field :request_id, type: String
|
|
11
|
+
|
|
12
|
+
index({ job_id: 1 }, { unique: true })
|
|
13
|
+
index({ request_id: 1 })
|
|
14
|
+
index({ created_at: 1 }, { expire_after_seconds: 86_400 }) # Auto-delete after 24 hours
|
|
15
|
+
|
|
16
|
+
validates :request_id, presence: true
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mongoid
|
|
4
|
+
module Auditor
|
|
5
|
+
class Railtie < Rails::Railtie
|
|
6
|
+
initializer 'mongoid_auditor.load_app' do
|
|
7
|
+
require 'mongoid/auditor/generators/install_generator' if defined?(Rails::Generators)
|
|
8
|
+
# Load controller concerns
|
|
9
|
+
ActiveSupport.on_load(:action_controller) do
|
|
10
|
+
require File.expand_path('../../../lib/mongoid/auditor/helpers/controller_helpers/init_audit_log', __dir__)
|
|
11
|
+
require File.expand_path('../../../lib/mongoid/auditor/helpers/controller_helpers/audit_controller_error_log', __dir__)
|
|
12
|
+
require File.expand_path('../../../lib/mongoid/auditor/helpers/controller_helpers/controller_audit_helper', __dir__)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Load job concerns
|
|
16
|
+
ActiveSupport.on_load(:active_job) do
|
|
17
|
+
require File.expand_path('../../../lib/mongoid/auditor/helpers/jobs/concerns/init_job_audit_log', __dir__)
|
|
18
|
+
require File.expand_path('../../../lib/mongoid/auditor/helpers/jobs/concerns/auditable_job_error', __dir__)
|
|
19
|
+
require File.expand_path('../../../lib/mongoid/auditor/helpers/jobs/auditor_job', __dir__)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Load models and model concerns
|
|
23
|
+
ActiveSupport.on_load(:mongoid) do
|
|
24
|
+
require File.expand_path('../../../lib/mongoid/auditor/helpers/models/concerns/audit_log_helpers', __dir__)
|
|
25
|
+
require File.expand_path('../../../lib/mongoid/auditor/helpers/models/concerns/auditable', __dir__)
|
|
26
|
+
require File.expand_path('../../../lib/mongoid/auditor/helpers/models/concerns/model_logs_helper', __dir__)
|
|
27
|
+
require File.expand_path('../../../lib/mongoid/auditor/helpers/models/audit_log', __dir__)
|
|
28
|
+
require File.expand_path('../../../lib/mongoid/auditor/helpers/models/request_context', __dir__)
|
|
29
|
+
require File.expand_path('../../../lib/mongoid/auditor/helpers/models/current', __dir__)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'mongoid/auditor/version'
|
|
4
|
+
require 'mongoid/auditor/configuration'
|
|
5
|
+
|
|
6
|
+
require 'active_support/current_attributes'
|
|
7
|
+
require 'mongoid/auditor/audit'
|
|
8
|
+
require 'mongoid/auditor/railtie' if defined?(Rails)
|
|
9
|
+
|
|
10
|
+
module Mongoid
|
|
11
|
+
module Auditor
|
|
12
|
+
class << self
|
|
13
|
+
attr_accessor :config
|
|
14
|
+
|
|
15
|
+
def configure
|
|
16
|
+
self.config ||= Configuration.new
|
|
17
|
+
yield(config)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|