loggable_activity 0.1.36

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.
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