loggable_activity 0.1.36

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/.DS_Store +0 -0
  3. data/.rspec +3 -0
  4. data/.rspec_status +0 -0
  5. data/.rubocop.yml +35 -0
  6. data/CHANGELOG.md +5 -0
  7. data/CODE_OF_CONDUCT.md +84 -0
  8. data/CONSIDERTIONS.md +129 -0
  9. data/GETTING-STARTED.md +80 -0
  10. data/LICENSE.txt +21 -0
  11. data/README.md +32 -0
  12. data/ROADMAP.md +19 -0
  13. data/Rakefile +8 -0
  14. data/lib/.DS_Store +0 -0
  15. data/lib/generators/.DS_Store +0 -0
  16. data/lib/generators/loggable_activity/.DS_Store +0 -0
  17. data/lib/generators/loggable_activity/install_generator.rb +30 -0
  18. data/lib/generators/loggable_activity/templates/.DS_Store +0 -0
  19. data/lib/generators/loggable_activity/templates/create_loggable_activities.rb +15 -0
  20. data/lib/generators/loggable_activity/templates/create_loggable_encryption_keys.rb +11 -0
  21. data/lib/generators/loggable_activity/templates/create_loggable_payloads.rb +15 -0
  22. data/lib/generators/loggable_activity/templates/current_user.rb +26 -0
  23. data/lib/generators/loggable_activity/templates/loggable_activity.en.yml +36 -0
  24. data/lib/loggable_activity/.DS_Store +0 -0
  25. data/lib/loggable_activity/activity.rb +124 -0
  26. data/lib/loggable_activity/configuration.rb +13 -0
  27. data/lib/loggable_activity/encryption.rb +43 -0
  28. data/lib/loggable_activity/encryption_key.rb +46 -0
  29. data/lib/loggable_activity/hooks.rb +152 -0
  30. data/lib/loggable_activity/payload.rb +71 -0
  31. data/lib/loggable_activity/payloads_builder.rb +89 -0
  32. data/lib/loggable_activity/update_payloads_builder.rb +99 -0
  33. data/lib/loggable_activity/version.rb +5 -0
  34. data/lib/loggable_activity.rb +18 -0
  35. data/loggable_activity-0.1.32.gem +0 -0
  36. data/loggable_activity-0.1.33.gem +0 -0
  37. data/loggable_activity-0.1.34.gem +0 -0
  38. data/pkg/loggable_activity-0.1.35.gem +0 -0
  39. data/sig/loggable_activity.rbs +4 -0
  40. metadata +105 -0
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This is the activity log. It contains an agregation of payloads.
4
+ # It reprecent one activity for the log
5
+
6
+ module LoggableActivity
7
+ class Activity < ActiveRecord::Base
8
+ self.table_name = 'loggable_activities'
9
+ has_many :payloads, class_name: 'LoggableActivity::Payload', dependent: :destroy
10
+ accepts_nested_attributes_for :payloads
11
+
12
+ validates :actor, presence: true
13
+ validates :action, presence: true
14
+ # validates :encrypted_record_display_name, presence: true
15
+ # validates :encrypted_actor_display_name, presence: true
16
+
17
+ validate :must_have_at_least_one_payload
18
+
19
+ belongs_to :record, polymorphic: true, optional: true
20
+ belongs_to :actor, polymorphic: true, optional: true
21
+
22
+ def attrs
23
+ # @attrs ||= payloads_attrs
24
+ payloads_attrs
25
+ end
26
+
27
+ def update_activity_attrs
28
+ {
29
+ update_attrs:,
30
+ updated_relations_attrs:
31
+ }
32
+ end
33
+
34
+ def primary_payload_attrs
35
+ primary_payload ? primary_payload.attrs : {}
36
+ end
37
+
38
+ def primary_payload
39
+ # @primary_payload ||= ordered_payloads.find { |p| p.payload_type == 'primary_payload' }
40
+ ordered_payloads.find { |p| p.payload_type == 'primary_payload' }
41
+ end
42
+
43
+ def ordered_payloads
44
+ # @ordered_payloads ||= payloads.order(:payload_type)
45
+ payloads.order(:payload_type)
46
+ end
47
+
48
+ def relations_attrs
49
+ attrs.filter { |p| p[:payload_type] == 'current_association' }
50
+ end
51
+
52
+ def updated_relations_attrs
53
+ grouped_associations = attrs.group_by { |p| p[:record_class] }
54
+
55
+ grouped_associations.map do |record_class, payloads|
56
+ previous_attrs = payloads.find { |p| p[:payload_type] == 'previous_association' }
57
+ current_attrs = payloads.find { |p| p[:payload_type] == 'current_association' }
58
+ next if previous_attrs.nil? && current_attrs.nil?
59
+
60
+ { record_class:, previous_attrs:, current_attrs: }
61
+ end.compact
62
+ end
63
+
64
+ def payloads_attrs
65
+ ordered_payloads.map do |payload|
66
+ {
67
+ record_class: payload.record_type,
68
+ payload_type: payload.payload_type,
69
+ attrs: payload.attrs
70
+ }
71
+ end
72
+ end
73
+
74
+ def update_attrs
75
+ update_payload_attrs = attrs.find { |p| p[:payload_type] == 'update_payload' }
76
+ return nil unless update_payload_attrs
77
+
78
+ update_payload_attrs.delete(:payload_type)
79
+ update_payload_attrs
80
+ end
81
+
82
+ def previous_associations_attrs
83
+ attrs.select { |p| p[:payload_type] == 'previous_association' }
84
+ end
85
+
86
+ def record_display_name
87
+ return I18n.t('loggable.activity.deleted') if encrypted_record_display_name.nil?
88
+
89
+ LoggableActivity::Encryption.decrypt(encrypted_record_display_name, record_key)
90
+ end
91
+
92
+ def actor_display_name
93
+ return I18n.t('loggable.activity.deleted') if encrypted_actor_display_name.nil?
94
+
95
+ LoggableActivity::Encryption.decrypt(encrypted_actor_display_name, actor_key)
96
+ end
97
+
98
+ def actor_key
99
+ LoggableActivity::EncryptionKey.for_record(actor)&.key
100
+ end
101
+
102
+ def record_key
103
+ LoggableActivity::EncryptionKey.for_record(record)&.key
104
+ end
105
+
106
+ def self.activities_for_actor(actor)
107
+ LoggableActivity::Activity.where(actor:).order(created_at: :desc)
108
+ end
109
+
110
+ def self.latest(limit = 20, params = { offset: 0 })
111
+ offset = params[:offset] || 0
112
+ LoggableActivity::Activity
113
+ .all
114
+ .order(created_at: :desc)
115
+ .includes(:payloads)
116
+ .offset(offset)
117
+ .limit(limit)
118
+ end
119
+
120
+ def must_have_at_least_one_payload
121
+ errors.add(:payloads, 'must have at least one payload') if payloads.empty?
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LoggableActivity
4
+ class Configuration
5
+ def self.load_config_file(config_file_path)
6
+ @config_data = YAML.load_file(config_file_path)
7
+ end
8
+
9
+ def self.for_class(class_name)
10
+ @config_data[class_name]
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This is a module for encryption and decryption of attributes
4
+ require 'openssl'
5
+ require 'base64'
6
+
7
+ module LoggableActivity
8
+ class EncryptionError < StandardError
9
+ end
10
+
11
+ module Encryption
12
+ def self.encrypt(data, encryption_key)
13
+ return nil if data.nil?
14
+ return nil if encryption_key.nil?
15
+ raise EncryptionError, 'Encryption failed: Invalid encryption key length' unless encryption_key.bytesize == 32
16
+
17
+ cipher = OpenSSL::Cipher.new('AES-128-CBC').encrypt
18
+ cipher.key = Digest::SHA1.hexdigest(encryption_key)[0..15]
19
+ encrypted = cipher.update(data.to_s) + cipher.final
20
+ Base64.encode64(encrypted)
21
+ rescue OpenSSL::Cipher::CipherError => e
22
+ raise EncryptionError, "Encryption failed: #{e.message} ***"
23
+ end
24
+
25
+ def self.decrypt(data, encryption_key)
26
+ return I18n.t('loggable.activity.deleted') if blank?(data) || blank?(encryption_key)
27
+
28
+ cipher = OpenSSL::Cipher.new('AES-128-CBC').decrypt
29
+ cipher.key = Digest::SHA1.hexdigest(encryption_key)[0..15]
30
+ decrypted_data = Base64.decode64(data)
31
+ decrypted_output = cipher.update(decrypted_data) + cipher.final
32
+ raise 'Decryption failed: Invalid UTF-8 output' unless decrypted_output.valid_encoding?
33
+
34
+ decrypted_output.force_encoding('UTF-8')
35
+ rescue OpenSSL::Cipher::CipherError => e
36
+ raise EncryptionError, e.message
37
+ end
38
+
39
+ def self.blank?(value)
40
+ value.respond_to?(:empty?) ? value.empty? : !value
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This the key used to unlock the data for one payload.
4
+ # When deleted only the encryption_key field is deleted.
5
+
6
+ module LoggableActivity
7
+ class EncryptionKey < ActiveRecord::Base
8
+ self.table_name = 'loggable_encryption_keys'
9
+ require 'securerandom'
10
+ belongs_to :record, polymorphic: true, optional: true
11
+ belongs_to :parrent_key, class_name: 'LoggableActivity::EncryptionKey', optional: true,
12
+ foreign_key: 'parrent_key_id'
13
+
14
+ def mark_as_deleted
15
+ update(key: nil)
16
+ parrent_key.mark_as_deleted if parrent_key.present?
17
+ end
18
+
19
+ def self.for_record_by_type_and_id(record_type, record_id, parrent_key = nil)
20
+ enctyption_key = find_by(record_type:, record_id:)
21
+
22
+ return enctyption_key if enctyption_key
23
+
24
+ create_encryption_key(record_type, record_id, parrent_key)
25
+ end
26
+
27
+ def self.for_record(record, parrent_key = nil)
28
+ encryption_key = find_by(record:)
29
+ return encryption_key if encryption_key
30
+
31
+ create_encryption_key(record.class.name, record.id, parrent_key)
32
+ end
33
+
34
+ def self.create_encryption_key(record_type, record_id, parrent_key = nil)
35
+ if parrent_key
36
+ create(record_type:, record_id:, key: random_key, parrent_key_id: parrent_key.id)
37
+ else
38
+ create(record_type:, record_id:, key: random_key)
39
+ end
40
+ end
41
+
42
+ def self.random_key
43
+ SecureRandom.hex(16)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,152 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This is the main module for loggable.
4
+ # When included to a model, it provides the features for creating the activities.
5
+ require 'loggable_activity/payloads_builder'
6
+ require 'loggable_activity/update_payloads_builder'
7
+
8
+ module LoggableActivity
9
+ module Hooks
10
+ extend ActiveSupport::Concern
11
+ include LoggableActivity::PayloadsBuilder
12
+ include LoggableActivity::UpdatePayloadsBuilder
13
+
14
+ included do
15
+ config = LoggableActivity::Configuration.for_class(name)
16
+ if config.nil?
17
+ raise "Loggable::Configuration not found for #{name}, Please add it to 'config/loggable_activity.yaml'"
18
+ end
19
+
20
+ self.loggable_attrs = config&.fetch('loggable_attrs', []) || []
21
+ self.relations = config&.fetch('relations', []) || []
22
+ self.auto_log = config&.fetch('auto_log', []) || []
23
+ self.actor_display_name = config&.fetch('actor_display_name', nil)
24
+ self.record_display_name = config&.fetch('record_display_name', nil)
25
+
26
+ after_create :log_create_activity
27
+ after_update :log_update_activity
28
+ before_destroy :log_destroy_activity
29
+
30
+ # has_one: encryption_key, as: :encryption_key, class_name: 'LoggableActivity::EncryptionKey'
31
+ end
32
+
33
+ # This is the main method for logging activities.
34
+ # It is never called from the directly from the controller.
35
+ def log(action, actor: nil, params: {})
36
+ @action = action
37
+ @actor = actor || Thread.current[:current_user]
38
+ # LoggableActivity::EncryptionKey.for_record(self)
39
+
40
+ return if @actor.nil?
41
+
42
+ @record = self
43
+ @params = params
44
+ @payloads = []
45
+
46
+ case action
47
+ when :create, :show
48
+ log_activity
49
+ when :destroy
50
+ log_destroy
51
+ when :update
52
+ log_update
53
+ else
54
+ log_custom_activity(action)
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ def log_activity
61
+ create_activity(build_payloads)
62
+ end
63
+
64
+ def log_update
65
+ create_activity(build_update_payloads)
66
+ end
67
+
68
+ def log_destroy
69
+ create_activity(build_destroy_payload)
70
+ end
71
+
72
+ def create_activity(payloads)
73
+ return if nothing_to_log?(payloads)
74
+
75
+ LoggableActivity::Activity.create!(
76
+ encrypted_actor_display_name: encrypted_actor_name,
77
+ encrypted_record_display_name: encrypted_record_name,
78
+ action: action_key,
79
+ actor: @actor,
80
+ record: @record,
81
+ payloads:
82
+ )
83
+ end
84
+
85
+ def nothing_to_log?(payloads)
86
+ payloads.empty?
87
+ end
88
+
89
+ def log_custom_activity(activity); end
90
+
91
+ def log_update_activity
92
+ log(:update) if self.class.auto_log.include?('update')
93
+ end
94
+
95
+ def log_create_activity
96
+ log(:create) if self.class.auto_log.include?('create')
97
+ end
98
+
99
+ def log_destroy_activity
100
+ LoggableActivity::EncryptionKey.for_record(self)&.mark_as_deleted
101
+ log(:destroy) if self.class.auto_log.include?('destroy')
102
+ end
103
+
104
+ def encrypted_actor_name
105
+ actor_display_name = @actor.send(actor_display_name_field)
106
+ LoggableActivity::Encryption.encrypt(actor_display_name, actor_encryption_key)
107
+ end
108
+
109
+ def encrypted_record_name
110
+ display_name =
111
+ if self.class.record_display_name.nil?
112
+ "#{self.class.name} id: #{id}"
113
+ else
114
+ send(self.class.record_display_name.to_sym)
115
+ end
116
+ LoggableActivity::Encryption.encrypt(display_name, primary_encryption_key)
117
+ end
118
+
119
+ def action_key
120
+ @action_key ||= self.class.base_action + ".#{@action}"
121
+ end
122
+
123
+ def primary_encryption_key
124
+ @primary_encryption_key ||=
125
+ LoggableActivity::EncryptionKey.for_record(self)&.key
126
+ end
127
+
128
+ def primary_encryption_key_deleted?
129
+ primary_encryption_key.nil?
130
+ end
131
+
132
+ def actor_encryption_key
133
+ LoggableActivity::EncryptionKey.for_record(@actor)&.key
134
+ end
135
+
136
+ def actor_display_name_field
137
+ Rails.application.config.loggable_activity.actor_display_name || "id: #{@actor.id}, class: #{@actor.class.name}"
138
+ end
139
+
140
+ def current_user_model?
141
+ Rails.application.config.loggable_activity.current_user_model_name == self.class.name
142
+ end
143
+
144
+ class_methods do
145
+ attr_accessor :loggable_attrs, :relations, :auto_log, :actor_display_name, :record_display_name
146
+
147
+ def base_action
148
+ name.downcase.gsub('::', '/')
149
+ end
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This is the payload of the log. It contains the encrypted data of one record in the DB.
4
+ # When the record is deleted, the encryption_key for the payload is deleted.
5
+ # Payloads comes in different flavors.
6
+ # The primary_payload is the payload that contains the parrent record.
7
+ # When fecthing the attrs, they are packed differently depending on the payload_type.
8
+
9
+ module LoggableActivity
10
+ class Payload < ActiveRecord::Base
11
+ self.table_name = 'loggable_payloads'
12
+ belongs_to :record, polymorphic: true, optional: true
13
+
14
+ belongs_to :activity
15
+ belongs_to :record, polymorphic: true, optional: true
16
+ validates :encrypted_attrs, presence: true
17
+ enum payload_type: {
18
+ primary_payload: 0,
19
+ update_payload: 1,
20
+ current_association: 2,
21
+ previous_association: 3
22
+ }
23
+
24
+ def attrs
25
+ return deleted_attrs if record.nil?
26
+
27
+ case payload_type
28
+ when 'current_association', 'primary_payload', 'previous_association'
29
+ decrypted_attrs
30
+ when 'update_payload'
31
+ decrypted_update_attrs
32
+ # when 'destroy_payload'
33
+ # destroy_payload_attrs
34
+ end
35
+ end
36
+
37
+ def payload_encryption_key
38
+ @payload_encryption_key ||= LoggableActivity::EncryptionKey.for_record(record)&.key
39
+ end
40
+
41
+ private
42
+
43
+ def deleted_attrs
44
+ encrypted_attrs.transform_values! { I18n.t('loggable.activity.deleted') }
45
+ end
46
+
47
+ def decrypted_update_attrs
48
+ encrypted_attrs['changes'].map do |change|
49
+ decrypted_from_to_attr(change)
50
+ end
51
+ end
52
+
53
+ def decrypted_from_to_attr(change)
54
+ change.to_h do |key, value|
55
+ from = decrypt_attr(value['from'])
56
+ to = decrypt_attr(value['to'])
57
+ [key, { from:, to: }]
58
+ end
59
+ end
60
+
61
+ def decrypted_attrs
62
+ encrypted_attrs.each do |key, value|
63
+ encrypted_attrs[key] = decrypt_attr(value)
64
+ end
65
+ end
66
+
67
+ def decrypt_attr(value)
68
+ LoggableActivity::Encryption.decrypt(value, payload_encryption_key)
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This is a factory for building payloads.
4
+
5
+ module LoggableActivity
6
+ module PayloadsBuilder
7
+ def build_payloads
8
+ build_primary_payload
9
+ self.class.relations.each do |relation_config|
10
+ build_relation_payload(relation_config)
11
+ end
12
+ @payloads
13
+ end
14
+
15
+ def build_primary_payload
16
+ encrypted_attrs = encrypt_attrs(attributes, self.class.loggable_attrs, primary_encryption_key)
17
+ @payloads << LoggableActivity::Payload.new(
18
+ record: @record,
19
+ payload_type: 'primary_payload',
20
+ encrypted_attrs:,
21
+ data_owner: true
22
+ )
23
+ end
24
+
25
+ def build_destroy_payload
26
+ encrypted_attrs = encrypt_attrs(attributes, self.class.loggable_attrs, primary_encryption_key)
27
+ encrypted_attrs.transform_values! { '*** DELETED ***' }
28
+ @payloads << LoggableActivity::Payload.new(
29
+ record: @record,
30
+ payload_type: 'primary_payload',
31
+ encrypted_attrs:,
32
+ data_owner: true
33
+ )
34
+ end
35
+
36
+ def build_relation_payload(relation_config)
37
+ relation_config.each_key do |key|
38
+ case key
39
+ when 'belongs_to'
40
+ build_payload(relation_config, 'belongs_to')
41
+ when 'has_one'
42
+ build_payload(relation_config, 'has_one')
43
+ end
44
+ end
45
+ end
46
+
47
+ def build_payload(relation_config, ralation_type)
48
+ associated_record = send(relation_config[ralation_type])
49
+ return nil if associated_record.nil?
50
+
51
+ associated_loggable_attrs = relation_config['loggable_attrs']
52
+
53
+ encryption_key = associated_record_encryption_key(associated_record, relation_config['data_owner'])
54
+
55
+ encrypted_attrs =
56
+ encrypt_attrs(
57
+ associated_record.attributes,
58
+ associated_loggable_attrs,
59
+ encryption_key.key
60
+ )
61
+
62
+ @payloads << LoggableActivity::Payload.new(
63
+ record: associated_record,
64
+ encrypted_attrs:,
65
+ payload_type: 'current_association',
66
+ data_owner: relation_config['data_owner']
67
+ )
68
+ end
69
+
70
+ def associated_record_encryption_key(associated_record, data_owner)
71
+ if data_owner
72
+ LoggableActivity::EncryptionKey.for_record(associated_record, LoggableActivity::EncryptionKey.for_record(self))
73
+ else
74
+ LoggableActivity::EncryptionKey.for_record(associated_record)
75
+ end
76
+ end
77
+
78
+ def encrypt_attrs(attrs, loggable_attrs, encryption_key)
79
+ attrs = attrs.slice(*loggable_attrs)
80
+ encrypt_attr(attrs, encryption_key)
81
+ end
82
+
83
+ def encrypt_attr(attrs, encryption_key)
84
+ attrs.each do |key, value|
85
+ attrs[key] = LoggableActivity::Encryption.encrypt(value, encryption_key)
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This is a factory for building update payloads
4
+
5
+ module LoggableActivity
6
+ module UpdatePayloadsBuilder
7
+ def build_update_payloads
8
+ @update_payloads = []
9
+
10
+ previous_values, current_values = primary_update_attrs
11
+ build_primary_update_payload(previous_values, current_values)
12
+
13
+ self.class.relations.each do |relation_config|
14
+ build_update_relation_payloads(relation_config)
15
+ end
16
+ @update_payloads
17
+ end
18
+
19
+ def primary_update_attrs
20
+ previous_values = saved_changes.transform_values(&:first)
21
+ current_values = saved_changes.transform_values(&:last)
22
+
23
+ [previous_values, current_values]
24
+ end
25
+
26
+ def build_primary_update_payload(previous_values, current_values)
27
+ return if previous_values == current_values
28
+
29
+ encrypted_update_attrs = encrypted_update_attrs(previous_values, current_values)
30
+ @update_payloads << LoggableActivity::Payload.new(
31
+ record: @record,
32
+ payload_type: 'update_payload',
33
+ encrypted_attrs: encrypted_update_attrs
34
+ )
35
+ end
36
+
37
+ def encrypted_update_attrs(previous_values, current_values)
38
+ changes = []
39
+ changed_attrs = previous_values.slice(*self.class.loggable_attrs)
40
+ changed_attrs.each do |key, from_value|
41
+ from = LoggableActivity::Encryption.encrypt(from_value, primary_encryption_key)
42
+ to_value = current_values[key]
43
+ to = LoggableActivity::Encryption.encrypt(to_value, primary_encryption_key)
44
+ changes << { key => { from:, to: } }
45
+ end
46
+ { changes: }
47
+ end
48
+
49
+ def build_update_relation_payloads(relation_config)
50
+ relation_config.each_key do |key|
51
+ case key
52
+ when 'belongs_to'
53
+ build_relation_update_for_belongs_to(relation_config)
54
+ end
55
+ end
56
+ end
57
+
58
+ def build_relation_update_for_belongs_to(relation_config)
59
+ relation_id = "#{relation_config['belongs_to']}_id"
60
+ model_class_name = relation_config['model']
61
+ model_class = model_class_name.constantize
62
+
63
+ return unless saved_changes.include?(relation_id)
64
+
65
+ relation_id_changes = saved_changes[relation_id]
66
+ previous_relation_id, current_relation_id = relation_id_changes
67
+
68
+ [previous_relation_id, current_relation_id].each_with_index do |id, index|
69
+ relation_record = id ? model_class.find_by(id:) : nil
70
+ next unless relation_record
71
+
72
+ payload_type = index.zero? ? 'previous_association' : 'current_association'
73
+ build_relation_update_payload(
74
+ relation_record.attributes,
75
+ relation_config['loggable_attrs'],
76
+ relation_record,
77
+ payload_type
78
+ )
79
+ end
80
+ end
81
+
82
+ def build_relation_update_payload(_attrs, loggable_attrs, record, payload_type)
83
+ encryption_key = LoggableActivity::EncryptionKey.for_record(record)&.key
84
+ encrypted_attrs = relation_encrypted_attrs(record.attributes, loggable_attrs, encryption_key)
85
+
86
+ ap "building relation update payload for #{record.id} with encryption_key: #{encryption_key}"
87
+
88
+ @update_payloads << LoggableActivity::Payload.new(
89
+ record:,
90
+ encrypted_attrs:,
91
+ payload_type:
92
+ )
93
+ end
94
+
95
+ def relation_encrypted_attrs(attrs, loggable_attrs, encryption_key)
96
+ encrypt_attrs(attrs, loggable_attrs, encryption_key)
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LoggableActivity
4
+ VERSION = '0.1.36'
5
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ # require 'rails'
4
+
5
+ require_relative 'loggable_activity/activity'
6
+ require_relative 'loggable_activity/configuration'
7
+ require_relative 'loggable_activity/encryption'
8
+ require_relative 'loggable_activity/encryption_key'
9
+ require_relative 'loggable_activity/hooks'
10
+ require_relative 'loggable_activity/payload'
11
+ require_relative 'loggable_activity/payloads_builder'
12
+ require_relative 'loggable_activity/update_payloads_builder'
13
+ require_relative 'loggable_activity/version'
14
+
15
+ module LoggableActivity
16
+ class Error < StandardError; end
17
+ # Your code goes here...
18
+ end
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,4 @@
1
+ module LoggableActivity
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end