effective_logging 3.0.9 → 3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 87ea6d6a2184d29eec7b23d56bde3f84c17f16b8f6058a9823849c5ee56edc50
4
- data.tar.gz: 0bb7c7040965bc8bb4587a1668d01902b4c85d26c574269b7b130a41325a570e
3
+ metadata.gz: 91790ca464dd429fb345fcbef0d15cbdebefdbd56f8685aaa8206653a7cd4350
4
+ data.tar.gz: fccd38fd9967c82487436ed7a25154bc7b84a4fc30c129691ce532683a951717
5
5
  SHA512:
6
- metadata.gz: 4c7d6f2d933d8774ebc5142a3e171e03178d5918a392635db966c9aa88b0d6d19127520d644fa2f43733cefc514bb31fb23d68dc542c99133b90922cf5aaa213
7
- data.tar.gz: 8914c55bdfbe4e3951e25152c095656c2fb649ebd91d3cceca73191b16177f45db31a14339c42363d223a571cefcf9bf1644f7c9683de43d001ea3ff371a6c8b
6
+ metadata.gz: 57df8caf9cf1a316d2a4591f28ca072b08fa2fae0da1bf71cdd72474971e16637d60337eeb9ce903bfe35033c1fcf68fb7ed76e022aab47a8a7503289fd8cbbc
7
+ data.tar.gz: 0b6106eade70761e9d71602846c5000308533de2058a6f8097e8aec22439155e5e55c83fafeeaf6a7e9c9339ec19cdd17cb15b372e3b3d79a1dc623eaf8b8bdf
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright 2019 Code and Effect Inc.
1
+ Copyright 2021 Code and Effect Inc.
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -197,19 +197,17 @@ This logging includes the resource's base attributes, all autosaved associations
197
197
 
198
198
  It will recurse through all accepts_nested_attributes has_many's and handle any number of child objects.
199
199
 
200
- Add to your model:
200
+ Add to your application controller:
201
201
 
202
- ```ruby
203
- class Post < ActiveRecord::Base
204
- log_changes
205
- end
202
+ ```
203
+ around_action :set_effective_logging_current_user
206
204
  ```
207
205
 
208
- and to your controller:
206
+ Add to your model:
209
207
 
210
208
  ```ruby
211
- class ApplicationController < ActionController::Base
212
- before_action :set_effective_logging_current_user
209
+ class Post < ActiveRecord::Base
210
+ log_changes
213
211
  end
214
212
  ```
215
213
 
@@ -371,4 +369,3 @@ MIT License. Copyright [Code and Effect Inc.](http://www.codeandeffect.com/)
371
369
  4. Push to the branch (`git push origin my-new-feature`)
372
370
  5. Bonus points for test coverage
373
371
  6. Create new Pull Request
374
-
@@ -1,21 +1,25 @@
1
1
  module Admin
2
2
  class LogsController < ApplicationController
3
- before_action :authenticate_user!
3
+ before_action(:authenticate_user!) if defined?(Devise)
4
+ before_action { EffectiveResources.authorize!(self, :admin, :effective_logging) }
5
+
6
+ include Effective::CrudController
4
7
  skip_log_page_views
5
8
 
6
- layout (EffectiveLogging.layout.kind_of?(Hash) ? EffectiveLogging.layout[:admin_logs] : EffectiveLogging.layout)
9
+ if (config = EffectiveLogging.layout)
10
+ layout(config.kind_of?(Hash) ? config[:admin] : config)
11
+ end
7
12
 
8
13
  def index
14
+ EffectiveResources.authorize!(self, :index, Effective::Log)
9
15
  @datatable = EffectiveLogsDatatable.new(self)
10
-
11
16
  @page_title = 'Logs'
12
-
13
- EffectiveLogging.authorize!(self, :index, Effective::Log)
14
- EffectiveLogging.authorize!(self, :admin, :effective_logging)
15
17
  end
16
18
 
17
19
  def show
18
20
  @log = Effective::Log.includes(:logs).find(params[:id])
21
+ EffectiveResources.authorize!(self, :show, @log)
22
+
19
23
  @log.next_log = Effective::Log.order(:id).where(parent_id: @log.parent_id).where('id > ?', @log.id).first
20
24
  @log.prev_log = Effective::Log.order(:id).where(parent_id: @log.parent_id).where('id < ?', @log.id).last
21
25
 
@@ -25,8 +29,6 @@ module Admin
25
29
  @log.datatable = EffectiveLogsDatatable.new(self, log_id: @log.id)
26
30
  end
27
31
 
28
- EffectiveLogging.authorize!(self, :show, @log)
29
- EffectiveLogging.authorize!(self, :admin, :effective_logging)
30
32
  end
31
33
  end
32
34
  end
@@ -1,11 +1,17 @@
1
1
  module Effective
2
2
  class LogsController < ApplicationController
3
+ before_action(:authenticate_user!, only: [:index, :show]) if defined?(Devise)
4
+
5
+ include Effective::CrudController
3
6
  skip_log_page_views
4
- before_action :authenticate_user!, only: [:index, :show]
7
+
8
+ if (config = EffectiveLogging.layout)
9
+ layout(config.kind_of?(Hash) ? config[:application] : config)
10
+ end
5
11
 
6
12
  # This is a post from our Javascript
7
13
  def create
8
- EffectiveLogging.authorize!(self, :create, Effective::Log.new)
14
+ EffectiveResources.authorize!(self, :create, Effective::Log.new)
9
15
 
10
16
  @log = Effective::Log.new.tap do |log|
11
17
  log.message = log_params[:message]
@@ -34,7 +40,7 @@ module Effective
34
40
 
35
41
  # This is the User index event
36
42
  def index
37
- EffectiveLogging.authorize!(self, :index, Effective::Log.new(user_id: current_user.id))
43
+ EffectiveResources.authorize!(self, :index, Effective::Log.new(user_id: current_user.id))
38
44
 
39
45
  @datatable = EffectiveLogsDatatable.new(self, user_id: current_user.id)
40
46
  end
@@ -7,10 +7,8 @@ class EffectiveLogsDatatable < Effective::Datatable
7
7
 
8
8
  if attributes[:user] == false
9
9
  # Do not include
10
- elsif attributes[:for]
11
- col :user, search: :string
12
10
  else
13
- col :user
11
+ col :user, search: :string
14
12
  end
15
13
 
16
14
  unless attributes[:status] == false
@@ -27,8 +27,8 @@ module ActsAsLoggable
27
27
  except: Array(@acts_as_loggable_options[:except])
28
28
  }
29
29
 
30
- if name == 'User'
31
- log_changes_options[:except] += %i(sign_in_count current_sign_in_at current_sign_in_ip last_sign_in_at last_sign_in_ip encrypted_password remember_created_at reset_password_token invitation_sent_at invitation_created_at invitation_token)
30
+ if name.end_with?('User')
31
+ log_changes_options[:except] += %i(sign_in_count current_sign_in_at current_sign_in_ip last_sign_in_at last_sign_in_ip encrypted_password remember_created_at reset_password_token invitation_sent_at invitation_created_at invitation_token access_token refresh_token token_expires_at)
32
32
  end
33
33
 
34
34
  self.send(:define_method, :log_changes_options) { log_changes_options }
@@ -67,4 +67,3 @@ module ActsAsLoggable
67
67
  end
68
68
 
69
69
  end
70
-
@@ -11,33 +11,36 @@ module Effective
11
11
  belongs_to :parent, class_name: 'Effective::Log', counter_cache: true, optional: true
12
12
  has_many :logs, class_name: 'Effective::Log', foreign_key: :parent_id
13
13
 
14
- belongs_to :user, optional: true
14
+ belongs_to :user, polymorphic: true, optional: true
15
15
  belongs_to :changes_to, polymorphic: true, optional: true # This is the log_changes to: option
16
16
  belongs_to :associated, polymorphic: true, optional: true
17
17
 
18
- serialize :details, Hash
18
+ effective_resource do
19
+ logs_count :integer # Rails Counter Cache
20
+
21
+ changes_to_type :string
22
+ changes_to_id :string
19
23
 
20
- # Attributes
21
- # logs_count :integer # Rails Counter Cache
24
+ associated_type :string
25
+ associated_id :integer
26
+ associated_to_s :string
22
27
 
23
- # changes_to_type :string
24
- # changes_to_id :string
28
+ status :string
29
+ message :text
30
+ details :text
25
31
 
26
- # associated_type :string
27
- # associated_id :integer
28
- # associated_to_s :string
29
- # message :text
30
- # details :text
31
- # status :string
32
- # timestamps
32
+ timestamps
33
+ end
34
+
35
+ serialize :details, Hash
33
36
 
34
37
  validates :message, presence: true
35
38
  validates :status, presence: true, inclusion: { in: EffectiveLogging.statuses }
36
39
 
37
40
  scope :deep, -> { includes(:user, :associated) }
38
41
  scope :sorted, -> { order(:id) }
39
- scope :logged_changes, -> { where(status: EffectiveLogging.log_changes_status)}
40
- scope :changes, -> { where(status: EffectiveLogging.log_changes_status)}
42
+ scope :logged_changes, -> { where(status: EffectiveLogging.log_changes_status) }
43
+ scope :changes, -> { where(status: EffectiveLogging.log_changes_status) }
41
44
 
42
45
  def to_s
43
46
  "Log #{id}"
@@ -63,5 +66,3 @@ module Effective
63
66
 
64
67
  end
65
68
  end
66
-
67
-
@@ -6,7 +6,7 @@ class EffectiveLogger
6
6
 
7
7
  options = Hash(options).delete_if { |k, v| v.blank? }
8
8
 
9
- if options[:user].present? && !options[:user].kind_of?(User)
9
+ if options[:user].present? && !options[:user].class.name.end_with?('User')
10
10
  raise ArgumentError.new('Log.log :user => ... argument must be a User object')
11
11
  end
12
12
 
@@ -30,6 +30,7 @@ class EffectiveLogger
30
30
  message: message,
31
31
  status: status,
32
32
  user_id: options.delete(:user_id),
33
+ user_type: options.delete(:user_type),
33
34
  user: options.delete(:user),
34
35
  parent: options.delete(:parent),
35
36
  associated: options.delete(:associated),
@@ -40,7 +40,7 @@
40
40
  - next unless value.present?
41
41
  .row
42
42
  .col-md-12
43
- %p
43
+ .mt-3
44
44
  %strong= "#{key.to_s.titleize}:"
45
45
  = format_log_details_value(log, key)
46
46
 
@@ -50,4 +50,3 @@
50
50
 
51
51
  - unless log.datatable.nil?
52
52
  = render_datatable(log.datatable)
53
-
@@ -2,37 +2,11 @@ EffectiveLogging.setup do |config|
2
2
  # Configure Database Tables
3
3
  config.logs_table_name = :logs
4
4
 
5
- # Authorization Method
6
- #
7
- # This method is called by all controller actions with the appropriate action and resource
8
- # If the method returns false, an Effective::AccessDenied Error will be raised (see README.md for complete info)
9
- #
10
- # Use via Proc (and with CanCan):
11
- # config.authorization_method = Proc.new { |controller, action, resource| can?(action, resource) }
12
- #
13
- # Use via custom method:
14
- # config.authorization_method = :my_authorization_method
15
- #
16
- # And then in your application_controller.rb:
17
- #
18
- # def my_authorization_method(action, resource)
19
- # current_user.is?(:admin)
20
- # end
21
- #
22
- # Or disable the check completely:
23
- # config.authorization_method = false
24
- config.authorization_method = Proc.new { |controller, action, resource| authorize!(action, resource) } # CanCanCan
25
-
26
5
  # Admin Screens Layout Settings
27
- config.layout = 'application' # All EffectiveLogging controllers will use this layout
28
-
29
- # config.layout = {
30
- # logs: 'application',
31
- # admin_logs: 'admin',
32
- # }
6
+ # config.layout = { application: 'application', admin: 'admin' }
33
7
 
34
8
  # EffectiveLogger.info('my message') macros
35
- # The following statuses are already present: info, success, error, view, change, email, sign_in, sign_out
9
+ # The following exist: info, success, error, view, change, download, email, sign_in, sign_out
36
10
  # Add more here
37
11
  config.additional_statuses = []
38
12
 
@@ -40,6 +14,9 @@ EffectiveLogging.setup do |config|
40
14
  #### Automatic Logging Functionality ####
41
15
  #########################################
42
16
 
17
+ # Log all active storage downloads
18
+ config.active_storage_enabled = true
19
+
43
20
  # Log all sent emails
44
21
  config.email_enabled = true
45
22
 
@@ -3,6 +3,7 @@ class CreateEffectiveLogging < ActiveRecord::Migration[4.2]
3
3
  create_table <%= @logs_table_name %> do |t|
4
4
  t.integer :parent_id
5
5
 
6
+ t.string :user_type
6
7
  t.integer :user_id
7
8
 
8
9
  t.string :changes_to_type
@@ -3,53 +3,34 @@ require 'effective_logging/engine'
3
3
  require 'effective_logging/version'
4
4
 
5
5
  module EffectiveLogging
6
-
7
- # The following are all valid config keys
8
- mattr_accessor :logs_table_name
9
-
10
- mattr_accessor :authorization_method
11
- mattr_accessor :layout
12
- mattr_accessor :additional_statuses
13
-
14
- mattr_accessor :email_enabled
15
- mattr_accessor :sign_in_enabled
16
- mattr_accessor :sign_out_enabled
17
-
18
6
  mattr_accessor :supressed
19
7
 
20
- def self.setup
21
- yield self
8
+ def self.config_keys
9
+ [
10
+ :logs_table_name, :layout, :additional_statuses,
11
+ :active_storage_enabled, :email_enabled, :sign_in_enabled, :sign_out_enabled
12
+ ]
22
13
  end
23
14
 
24
- def self.authorized?(controller, action, resource)
25
- @_exceptions ||= [Effective::AccessDenied, (CanCan::AccessDenied if defined?(CanCan)), (Pundit::NotAuthorizedError if defined?(Pundit))].compact
26
-
27
- return !!authorization_method unless authorization_method.respond_to?(:call)
28
- controller = controller.controller if controller.respond_to?(:controller)
29
-
30
- begin
31
- !!(controller || self).instance_exec((controller || self), action, resource, &authorization_method)
32
- rescue *@_exceptions
33
- false
34
- end
35
- end
36
-
37
- def self.authorize!(controller, action, resource)
38
- raise Effective::AccessDenied unless authorized?(controller, action, resource)
39
- end
40
-
41
- def self.supressed(&block)
42
- @@supressed = true; yield; @@supressed = false
43
- end
44
-
45
- def self.supressed?
46
- @@supressed == true
47
- end
15
+ include EffectiveGem
48
16
 
49
17
  def self.statuses
50
18
  @statuses ||= (
51
- Array(@@additional_statuses).map { |status| status.to_s.downcase } | # union
52
- ['info', 'success', 'error', 'view', log_changes_status, ('email' if email_enabled), ('sign_in' if sign_in_enabled), ('sign_out' if sign_out_enabled)].compact
19
+ base = [
20
+ 'info',
21
+ 'success',
22
+ 'error',
23
+ 'view',
24
+ log_changes_status, # 'change'
25
+ ('download' if active_storage_enabled),
26
+ ('email' if email_enabled),
27
+ ('sign_in' if sign_in_enabled),
28
+ ('sign_out' if sign_out_enabled)
29
+ ].compact
30
+
31
+ additional = Array(additional_statuses).map { |status| status.to_s.downcase }
32
+
33
+ base | additional # union
53
34
  )
54
35
  end
55
36
 
@@ -59,11 +40,21 @@ module EffectiveLogging
59
40
 
60
41
  # This is set by the "set_effective_logging_current_user" before_filter.
61
42
  def self.current_user=(user)
62
- @effective_logging_current_user = user
43
+ Thread.current[:effective_logging_current_user] = user
63
44
  end
64
45
 
65
46
  def self.current_user
66
- @effective_logging_current_user
47
+ Thread.current[:effective_logging_current_user]
48
+ end
49
+
50
+ def self.supressed(&block)
51
+ Thread.current[:effective_logging_supressed] = true
52
+ yield
53
+ Thread.current[:effective_logging_supressed] = nil
54
+ end
55
+
56
+ def self.supressed?
57
+ Thread.current[:effective_logging_supressed] == true
67
58
  end
68
59
 
69
60
  end
@@ -0,0 +1,23 @@
1
+ module EffectiveLogging
2
+ module ActiveStorageLogger
3
+
4
+ def track_downloads
5
+ user = current_user if respond_to?(:current_user)
6
+
7
+ key = decode_verified_key()
8
+ return unless key.present?
9
+
10
+ blob = ActiveStorage::Blob.where(key: key[:key]).first
11
+ return unless blob.present?
12
+
13
+ blob.attachments.each do |attachment|
14
+ associated = attachment.record
15
+ filename = blob.filename.to_s
16
+ message = [associated.to_s, filename.to_s].uniq.join(' ')
17
+
18
+ EffectiveLogger.download(message, associated: associated, filename: filename, user: user)
19
+ end
20
+ end
21
+
22
+ end
23
+ end
@@ -5,30 +5,56 @@ module EffectiveLogging
5
5
  return unless message.present?
6
6
 
7
7
  # collect a Hash of arguments used to invoke EffectiveLogger.success
8
- logged_fields = { from: message.from.join(','), to: message.to, subject: message.subject }
8
+ fields = { from: message.from.join(','), to: message.to, subject: message.subject, cc: message.cc, bcc: message.bcc }
9
9
 
10
10
  # Add a log header to your mailer to pass some objects or additional things to EffectiveLogger
11
11
  # mail(to: 'admin@example.com', subject: @post.title, log: { post: @post })
12
12
  if message.header['log'].present?
13
13
  # This is a bit sketchy, but gives access to the object in Rails 4.2 anyway
14
- logged_fields.merge!(message.header['log'].instance_variable_get(:@value) || {})
14
+ fields.merge!(message.header['log'].instance_variable_get(:@value) || {})
15
15
 
16
16
  # Get rid of the extra header, as it should not be set in the real mail message.
17
17
  message.header['log'] = nil
18
18
  end
19
19
 
20
+ # Pass a tenant to your mailer
21
+ # mail(to: 'admin@example.com', subject: @post.title, tenant: Tenant.current)
22
+ tenant = if message.header['tenant'].present?
23
+ value = message.header['tenant'].to_s.to_sym # OptionalField, not a String here
24
+ message.header['tenant'] = nil
25
+ value
26
+ end || (Tenant.current if defined?(Tenant))
27
+
28
+ user_klass = "#{tenant.to_s.classify}::User".safe_constantize
29
+
20
30
  body = (message.body.try(:parts) || []).find { |part| part.content_type.to_s.downcase.include?('text/html') }
31
+ body ||= message.body
21
32
 
22
- logged_fields[:email] = "#{message.header}<hr>#{(body.presence || message.body)}"
33
+ fields[:email] = "#{message.header}<hr>#{body}"
23
34
 
24
- (message.to || []).each do |to|
25
- user = (User.where(email: to).first rescue nil)
35
+ if tenant.present?
36
+ Tenant.as(tenant) { log_email(message, fields, user_klass) }
37
+ else
38
+ log_email(message, fields, user_klass)
39
+ end
40
+
41
+ true
42
+ end
26
43
 
27
- logged_fields[:to] = to
28
- logged_fields[:associated] ||= user
29
- logged_fields[:user] ||= user
44
+ private
45
+
46
+ def self.log_email(message, fields, user_klass)
47
+ tos = Array(message.to) - [nil, '']
48
+
49
+ tos.each do |to|
50
+ user = (user_klass.where(email: to.downcase).first if user_klass.present?)
51
+
52
+ user_fields = fields.merge(to: to, user: user, associated: user)
53
+ ::EffectiveLogger.email("#{message.subject} - #{tos.join(', ')}", user_fields)
54
+ end
30
55
 
31
- ::EffectiveLogger.email("#{message.subject} - #{message.to.join(', ')}", logged_fields)
56
+ if tos.blank? && (message.cc.present? || message.bcc.present?)
57
+ ::EffectiveLogger.email("#{message.subject} - multiple recipients", fields)
32
58
  end
33
59
  end
34
60
 
@@ -1,4 +1,5 @@
1
1
  require 'effective_logging/active_record_logger'
2
+ require 'effective_logging/active_storage_logger'
2
3
  require 'effective_logging/email_logger'
3
4
  require 'effective_logging/log_page_views'
4
5
  require 'effective_logging/set_current_user'
@@ -27,6 +28,16 @@ module EffectiveLogging
27
28
  end
28
29
  end
29
30
 
31
+ # Log all ActiveStorage downloads
32
+ initializer 'effective_logging.active_storage' do |app|
33
+ if EffectiveLogging.active_storage_enabled == true && defined?(ActiveStorage)
34
+ Rails.application.config.to_prepare do
35
+ ActiveStorage::DiskController.include(EffectiveLogging::ActiveStorageLogger)
36
+ ActiveStorage::DiskController.class_eval { after_action(:track_downloads, only: :show) }
37
+ end
38
+ end
39
+ end
40
+
30
41
  # Register the log_page_views concern so that it can be called in ActionController or elsewhere
31
42
  initializer 'effective_logging.log_changes_action_controller' do |app|
32
43
  Rails.application.config.to_prepare do
@@ -39,7 +39,7 @@ module EffectiveLogging
39
39
  return if @_effective_logging_skip_log_page_view == true
40
40
  return if (self.class.log_page_views_opts[:skip_namespace] || []).include?(self.class.parent)
41
41
 
42
- user = EffectiveLogging.current_user || current_user
42
+ user = EffectiveLogging.current_user || (current_user if respond_to?(:current_user))
43
43
 
44
44
  if self.class.log_page_views_opts[:details] == false
45
45
  ::EffectiveLogger.view("#{request.request_method} #{request.path}", user: user)
@@ -66,4 +66,3 @@ module EffectiveLogging
66
66
 
67
67
  end
68
68
  end
69
-
@@ -3,13 +3,18 @@ module EffectiveLogging
3
3
  module ActionController
4
4
 
5
5
  # Add me to your ApplicationController
6
- # before_action :set_effective_logging_current_user
6
+ # around_action :set_effective_logging_current_user
7
7
 
8
8
  def set_effective_logging_current_user
9
9
  EffectiveLogging.current_user = current_user
10
+
11
+ if block_given?
12
+ retval = yield
13
+ EffectiveLogging.current_user = nil
14
+ retval
15
+ end
10
16
  end
11
17
 
12
18
  end
13
19
  end
14
20
  end
15
-
@@ -1,3 +1,3 @@
1
1
  module EffectiveLogging
2
- VERSION = '3.0.9'.freeze
2
+ VERSION = '3.1.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: effective_logging
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.9
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Code and Effect
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-08-13 00:00:00.000000000 Z
11
+ date: 2021-02-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -112,6 +112,7 @@ files:
112
112
  - db/migrate/01_create_effective_logging.rb.erb
113
113
  - lib/effective_logging.rb
114
114
  - lib/effective_logging/active_record_logger.rb
115
+ - lib/effective_logging/active_storage_logger.rb
115
116
  - lib/effective_logging/email_logger.rb
116
117
  - lib/effective_logging/engine.rb
117
118
  - lib/effective_logging/log_page_views.rb