Class: Ditty::Listener

Inherits:
Object
  • Object
show all
Defined in:
lib/ditty/listener.rb

Constant Summary collapse

EVENTS =
%i[
  component_list component_create component_read component_update component_delete
  user_register user_login user_logout user_failed_login
  identity_update_password identity_update_password_failed
].freeze

Instance Method Summary collapse

Constructor Details

#initializeListener

Returns a new instance of Listener.



15
16
17
# File 'lib/ditty/listener.rb', line 15

def initialize
  @mutex = Mutex.new
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args) ⇒ Object



19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/ditty/listener.rb', line 19

def method_missing(method, *args)
  unless args[0].is_a?(Hash) && args[0][:target].is_a?(Sinatra::Base) && args[0][:target].settings.track_actions
    return
  end

  log_action(
    user_traits(args[0][:target]).merge(
      action: action_from(args[0][:target], method),
      details: args[0][:details]
    ).merge(args[0][:values] || {})
  )
end

Instance Method Details

#action_from(target, method) ⇒ Object



66
67
68
69
70
# File 'lib/ditty/listener.rb', line 66

def action_from(target, method)
  return method unless method.to_s.start_with? 'component_'

  target.class.to_s.demodulize.underscore + '_' + method.to_s.gsub(/^component_/, '')
end

#log_action(values) ⇒ Object



72
73
74
75
# File 'lib/ditty/listener.rb', line 72

def log_action(values)
  values[:user] ||= values[:target].current_user if values[:target]
  @mutex.synchronize { ::Ditty::AuditLog.create values }
end

#respond_to_missing?(method, _include_private = false) ⇒ Boolean

Returns:

  • (Boolean)


32
33
34
# File 'lib/ditty/listener.rb', line 32

def respond_to_missing?(method, _include_private = false)
  EVENTS.include? method
end

#user_login(event) ⇒ Object



36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/ditty/listener.rb', line 36

def (event)
  log_action(
    user_traits(event[:target]).merge(
      action: action_from(event[:target], :user_login),
      details: event[:details]
    ).merge(event[:values] || {})
  )

  @mutex.synchronize do
    UserLoginTrait.update_or_create(user_traits(event[:target]), updated_at: Time.now)
  end
end

#user_register(event) ⇒ Object



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/ditty/listener.rb', line 49

def user_register(event)
  user = event[:values][:user]
  log_action(
    user_traits(event[:target]).merge(
      user_id: user.id,
      action: action_from(event[:target], :user_register),
      details: event[:details]
    ).merge(event[:values] || {})
  )

  # Create the SA user if none is present
  sa = Role.find_or_create(name: 'super_admin')
  return if User.where(roles: sa).count.positive?

  user.add_role sa
end

#user_traits(target) ⇒ Object



77
78
79
80
81
82
83
84
85
# File 'lib/ditty/listener.rb', line 77

def user_traits(target)
  {
    user_id: target.current_user&.id,
    platform: target.browser.platform.name,
    device: target.browser.device.name,
    browser: target.browser.name,
    ip_address: target.request.ip
  }
end