Class: Magick::AuditLog::Entry

Inherits:
Object
  • Object
show all
Defined in:
lib/magick/audit_log.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(feature_name, action, user_id: nil, changes: {}, metadata: {}, timestamp: nil, id: nil) ⇒ Entry

Returns a new instance of Entry.



25
26
27
28
29
30
31
32
33
# File 'lib/magick/audit_log.rb', line 25

def initialize(feature_name, action, user_id: nil, changes: {}, metadata: {}, timestamp: nil, id: nil)
  @feature_name = feature_name.to_s
  @action = action.to_s
  @user_id = user_id
  @timestamp = timestamp || Time.now
  @changes = changes || {}
  @metadata =  || {}
  @id = (id.nil? || id.to_s.empty? ? self.class.generate_id(@timestamp) : id.to_s)
end

Instance Attribute Details

#action ⇒ Object (readonly)

Returns the value of attribute action.



23
24
25
# File 'lib/magick/audit_log.rb', line 23

def action
  @action
end

#changes ⇒ Object (readonly)

Returns the value of attribute changes.



23
24
25
# File 'lib/magick/audit_log.rb', line 23

def changes
  @changes
end

#feature_name ⇒ Object (readonly)

Returns the value of attribute feature_name.



23
24
25
# File 'lib/magick/audit_log.rb', line 23

def feature_name
  @feature_name
end

#id ⇒ Object (readonly)

Returns the value of attribute id.



23
24
25
# File 'lib/magick/audit_log.rb', line 23

def id
  @id
end

#metadata ⇒ Object (readonly)

Returns the value of attribute metadata.



23
24
25
# File 'lib/magick/audit_log.rb', line 23

def 
  @metadata
end

#timestamp ⇒ Object (readonly)

Returns the value of attribute timestamp.



23
24
25
# File 'lib/magick/audit_log.rb', line 23

def timestamp
  @timestamp
end

#user_id ⇒ Object (readonly)

Returns the value of attribute user_id.



23
24
25
# File 'lib/magick/audit_log.rb', line 23

def user_id
  @user_id
end

Class Method Details

.from_h(raw) ⇒ Object

Rebuild an entry from a stored hash. Adapters hand back string keys (Redis/JSON) or symbol keys (ActiveRecord), so accept both.



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/magick/audit_log.rb', line 73

def self.from_h(raw)
  data = raw.is_a?(Hash) ? raw : nil
  return nil unless data

  name = fetch(data, :feature_name)
  return nil if name.nil?

  new(
    name,
    fetch(data, :action),
    user_id: fetch(data, :user_id),
    changes: deep_symbolize(fetch(data, :changes)) || {},
    metadata: deep_symbolize(fetch(data, :metadata)) || {},
    timestamp: parse_time(fetch(data, :timestamp)),
    id: fetch(data, :id)
  )
end

.generate_id(timestamp) ⇒ Object

Sortable, collision-free id: milliseconds since the epoch, then a per-process sequence, then randomness. All fields are fixed width, so sorting ids as strings orders entries chronologically — including entries written in the same second, which the iso8601 timestamp (second resolution) cannot distinguish after a storage round trip.



52
53
54
55
56
57
58
59
# File 'lib/magick/audit_log.rb', line 52

def self.generate_id(timestamp)
  format(
    '%<millis>013d-%<sequence>09d-%<random>s',
    millis: (timestamp.to_f * 1000).floor,
    sequence: next_sequence,
    random: SecureRandom.hex(4)
  )
end

.next_sequence ⇒ Object



65
66
67
68
69
# File 'lib/magick/audit_log.rb', line 65

def self.next_sequence
  SEQUENCE_MUTEX.synchronize do
    @sequence = ((@sequence || 0) + 1) % SEQUENCE_LIMIT
  end
end

Instance Method Details

#to_h ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
# File 'lib/magick/audit_log.rb', line 35

def to_h
  {
    id: id,
    feature_name: feature_name,
    action: action,
    user_id: user_id,
    timestamp: timestamp.iso8601,
    changes: changes,
    metadata: 
  }
end