loggable_activity 0.5.4 → 0.5.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (137) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +10 -0
  3. data/CHANGELOG.md +12 -3
  4. data/GETTING-STARTED.md +61 -0
  5. data/README.md +4 -7
  6. data/app/views/loggable_activity/activities/_activities.html.slim +6 -6
  7. data/docker-compose.yml +27 -0
  8. data/docs/CHANGELOG_md.html +318 -0
  9. data/docs/CHEAT_SHEET_md.html +168 -0
  10. data/docs/CODE_OF_CONDUCT_md.html +250 -0
  11. data/docs/CreateLoggableActivities.html +175 -0
  12. data/docs/CreateLoggableActivityTables.html +173 -0
  13. data/docs/GETTING-STARTED_md.html +211 -0
  14. data/docs/Gemfile.html +153 -0
  15. data/docs/Gemfile_lock.html +438 -0
  16. data/docs/LoggableActivity/ActivitiesController.html +160 -0
  17. data/docs/LoggableActivity/ActivitiesHelper.html +158 -0
  18. data/docs/LoggableActivity/Activity.html +565 -0
  19. data/docs/LoggableActivity/ApplicationController.html +97 -0
  20. data/docs/LoggableActivity/ApplicationHelper.html +91 -0
  21. data/docs/LoggableActivity/ApplicationJob.html +97 -0
  22. data/docs/LoggableActivity/ApplicationMailer.html +97 -0
  23. data/docs/LoggableActivity/ApplicationRecord.html +97 -0
  24. data/docs/LoggableActivity/Configuration.html +237 -0
  25. data/docs/LoggableActivity/ConfigurationError.html +142 -0
  26. data/docs/LoggableActivity/CurrentActor.html +166 -0
  27. data/docs/LoggableActivity/DataOwner.html +138 -0
  28. data/docs/LoggableActivity/Encryption.html +321 -0
  29. data/docs/LoggableActivity/EncryptionError.html +142 -0
  30. data/docs/LoggableActivity/EncryptionKey.html +399 -0
  31. data/docs/LoggableActivity/Engine.html +108 -0
  32. data/docs/LoggableActivity/Error.html +142 -0
  33. data/docs/LoggableActivity/Generators/InstallGenerator.html +212 -0
  34. data/docs/LoggableActivity/Generators.html +91 -0
  35. data/docs/LoggableActivity/Hooks.html +841 -0
  36. data/docs/LoggableActivity/Payload.html +430 -0
  37. data/docs/LoggableActivity/Sanitizer.html +134 -0
  38. data/docs/LoggableActivity/Services/BasePayloadsBuilder.html +472 -0
  39. data/docs/LoggableActivity/Services/CustomPayloadsBuilder.html +225 -0
  40. data/docs/LoggableActivity/Services/DestroyPayloadsBuilder.html +396 -0
  41. data/docs/LoggableActivity/Services/PayloadsBuilder.html +348 -0
  42. data/docs/LoggableActivity/Services/UpdatePayloadsBuilder.html +540 -0
  43. data/docs/LoggableActivity/Services.html +93 -0
  44. data/docs/LoggableActivity.html +173 -0
  45. data/docs/MIT-LICENSE.html +132 -0
  46. data/docs/Object.html +110 -0
  47. data/docs/README_md.html +186 -0
  48. data/docs/Rakefile.html +134 -0
  49. data/docs/app/assets/config/loggable_activity_manifest_js.html +126 -0
  50. data/docs/app/assets/javascripts/loggable_activity/application_js.html +124 -0
  51. data/docs/app/assets/stylesheets/loggable_activity/activities_scss.html +154 -0
  52. data/docs/app/assets/stylesheets/loggable_activity/application_scss.html +142 -0
  53. data/docs/app/views/layouts/loggable_activity/application_html_slim.html +145 -0
  54. data/docs/app/views/loggable_activity/activities/_activities_html_slim.html +159 -0
  55. data/docs/created.rid +74 -0
  56. data/docs/css/fonts.css +167 -0
  57. data/docs/css/rdoc.css +687 -0
  58. data/docs/fonts/Lato-Light.ttf +0 -0
  59. data/docs/fonts/Lato-LightItalic.ttf +0 -0
  60. data/docs/fonts/Lato-Regular.ttf +0 -0
  61. data/docs/fonts/Lato-RegularItalic.ttf +0 -0
  62. data/docs/fonts/SourceCodePro-Bold.ttf +0 -0
  63. data/docs/fonts/SourceCodePro-Regular.ttf +0 -0
  64. data/docs/git-org/HEAD.html +126 -0
  65. data/docs/git-org/config.html +128 -0
  66. data/docs/git-org/description.html +126 -0
  67. data/docs/git-org/hooks/applypatch-msg_sample.html +128 -0
  68. data/docs/git-org/hooks/commit-msg_sample.html +138 -0
  69. data/docs/git-org/hooks/fsmonitor-watchman_sample.html +302 -0
  70. data/docs/git-org/hooks/post-update_sample.html +128 -0
  71. data/docs/git-org/hooks/pre-applypatch_sample.html +128 -0
  72. data/docs/git-org/hooks/pre-commit_sample.html +174 -0
  73. data/docs/git-org/hooks/pre-merge-commit_sample.html +133 -0
  74. data/docs/git-org/hooks/pre-push_sample.html +161 -0
  75. data/docs/git-org/hooks/pre-rebase_sample.html +282 -0
  76. data/docs/git-org/hooks/pre-receive_sample.html +144 -0
  77. data/docs/git-org/hooks/prepare-commit-msg_sample.html +136 -0
  78. data/docs/git-org/hooks/push-to-checkout_sample.html +178 -0
  79. data/docs/git-org/hooks/update_sample.html +226 -0
  80. data/docs/git-org/info/exclude.html +126 -0
  81. data/docs/images/add.png +0 -0
  82. data/docs/images/arrow_up.png +0 -0
  83. data/docs/images/brick.png +0 -0
  84. data/docs/images/brick_link.png +0 -0
  85. data/docs/images/bug.png +0 -0
  86. data/docs/images/bullet_black.png +0 -0
  87. data/docs/images/bullet_toggle_minus.png +0 -0
  88. data/docs/images/bullet_toggle_plus.png +0 -0
  89. data/docs/images/date.png +0 -0
  90. data/docs/images/delete.png +0 -0
  91. data/docs/images/find.png +0 -0
  92. data/docs/images/loadingAnimation.gif +0 -0
  93. data/docs/images/macFFBgHack.png +0 -0
  94. data/docs/images/package.png +0 -0
  95. data/docs/images/page_green.png +0 -0
  96. data/docs/images/page_white_text.png +0 -0
  97. data/docs/images/page_white_width.png +0 -0
  98. data/docs/images/plugin.png +0 -0
  99. data/docs/images/ruby.png +0 -0
  100. data/docs/images/tag_blue.png +0 -0
  101. data/docs/images/tag_green.png +0 -0
  102. data/docs/images/transparent.png +0 -0
  103. data/docs/images/wrench.png +0 -0
  104. data/docs/images/wrench_orange.png +0 -0
  105. data/docs/images/zoom.png +0 -0
  106. data/docs/index.html +166 -0
  107. data/docs/js/darkfish.js +97 -0
  108. data/docs/js/navigation.js +105 -0
  109. data/docs/js/navigation.js.gz +0 -0
  110. data/docs/js/search.js +110 -0
  111. data/docs/js/search_index.js +1 -0
  112. data/docs/js/search_index.js.gz +0 -0
  113. data/docs/js/searcher.js +229 -0
  114. data/docs/js/searcher.js.gz +0 -0
  115. data/docs/lib/loggable_activity/config_schema_json.html +205 -0
  116. data/docs/lib/tasks/loggable_activity_tasks_rake.html +128 -0
  117. data/docs/table_of_contents.html +954 -0
  118. data/lib/generators/loggable_activity/install/install_generator.rb +68 -0
  119. data/lib/generators/loggable_activity/install/templates/create_loggable_activities.rb +45 -0
  120. data/lib/generators/loggable_activity/install/templates/loggable_activity.en.yml +32 -0
  121. data/lib/generators/loggable_activity/install/templates/loggable_activity.rb +27 -0
  122. data/lib/generators/loggable_activity/install/templates/loggable_activity.yml +103 -0
  123. data/lib/loggable_activity/activity.rb +4 -4
  124. data/lib/loggable_activity/concerns/current_actor.rb +25 -0
  125. data/lib/loggable_activity/config_schema.json +2 -13
  126. data/lib/loggable_activity/configuration.rb +0 -10
  127. data/lib/loggable_activity/encryption.rb +33 -12
  128. data/lib/loggable_activity/encryption_key.rb +1 -1
  129. data/lib/loggable_activity/error.rb +3 -3
  130. data/lib/loggable_activity/hooks.rb +74 -18
  131. data/lib/loggable_activity/payload.rb +6 -4
  132. data/lib/loggable_activity/services/base_payloads_builder.rb +2 -1
  133. data/lib/loggable_activity/services/custom_payloads_builder.rb +55 -0
  134. data/lib/loggable_activity/version.rb +1 -1
  135. data/lib/loggable_activity.rb +5 -2
  136. metadata +121 -111
  137. data/lib/loggable_activity/concerns/current_user.rb +0 -26
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This module provides generators for installing and configuring LoggableActivity.
4
+ # It includes generators for creating initializer, migration, and locale files.
5
+ #
6
+ # Example usage:
7
+ # rails generate loggable_activity:install
8
+ #
9
+ # This will:
10
+ # - Create an initializer file in config/initializers/loggable_activity.rb
11
+ # - Create a migration file in db/migrate/
12
+ # - Create a locale file in config/locales/loggable_activity.en.yml
13
+ #
14
+ # After running the generator, remember to:
15
+ # - Add `mount LoggableActivity::Engine => '/loggable_activity'` to your routes.rb file.
16
+ # - Run `rails db:migrate` to create the necessary database tables.
17
+ # - Include `LoggableActivity::Hook` in the models you want to track.
18
+ # - Update the config/loggable_activity.yaml file with the fields you want to track.
19
+ # - Ensure the locale files are properly set up in config/locales/loggable_activity.en.yml.
20
+ module LoggableActivity
21
+ module Generators
22
+ # The InstallGenerator class is responsible for copying the necessary
23
+ # files to set up LoggableActivity in a Rails application.
24
+ class InstallGenerator < Rails::Generators::Base
25
+ source_root File.expand_path('templates', __dir__)
26
+
27
+ desc 'Creates a LoggableActivity initializer in your application.'
28
+ def copy_initializer
29
+ template 'loggable_activity.rb', 'config/initializers/loggable_activity.rb'
30
+ end
31
+
32
+ desc 'Creates a migration file for LoggableActivity in your application.'
33
+ def copy_migration
34
+ template 'create_loggable_activities.rb', "db/migrate/#{migration_number}_create_loggable_activities.rb"
35
+ end
36
+
37
+ desc 'Creates a locale file for LoggableActivity in your application.'
38
+ def copy_locale
39
+ template 'loggable_activity.en.yml', 'config/locales/loggable_activity.en.yml'
40
+ end
41
+
42
+ # Generates a timestamp to use in the migration filename.
43
+ #
44
+ # @return [String] the current UTC time formatted as a timestamp
45
+ def migration_number
46
+ Time.now.utc.strftime('%Y%m%d%H%M%S')
47
+ end
48
+
49
+ puts ''
50
+ puts "\e[1m\e[32m* ----------------------------- LoggableActivity ----------------------------- *\e[0m"
51
+ puts "\e[1m\e[32m* *\e[0m"
52
+ puts "\e[1m\e[32m* LoggableActivity has been successfully installed. *\e[0m"
53
+ puts "\e[1m\e[32m* Add the following to your routes.rb file. *\e[0m"
54
+ puts "\e[1m\e[32m* Mount LoggableActivity::Engine => '/loggable_activity' *\e[0m"
55
+ puts "\e[1m\e[32m* *\e[0m"
56
+ puts "\e[1m\e[32m* $ rails db:migrate to create the tables. *\e[0m"
57
+ puts "\e[1m\e[32m* *\e[0m"
58
+ puts "\e[1m\e[32m* Add include LoggableActivity::Hook to the models you want to track. *\e[0m"
59
+ puts "\e[1m\e[32m* *\e[0m"
60
+ puts "\e[1m\e[32m* Update the config/loggable_activity.yaml file with fields to track. *\e[0m"
61
+ puts "\e[1m\e[32m* *\e[0m"
62
+ puts "\e[1m\e[32m* Locale files are found in config/locale/loggable_activity.en.yaml. *\e[0m"
63
+ puts "\e[1m\e[32m* *\e[0m"
64
+ puts "\e[1m\e[32m* ---------------------------------------------------------------------------- *\e[0m"
65
+ puts ''
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This migration creates the necessary tables for LoggableActivity.
4
+ class CreateLoggableActivities < ActiveRecord::Migration[7.1]
5
+ def change
6
+ create_table :loggable_activity_encryption_keys do |t|
7
+ t.references :record, polymorphic: true, null: true, index: true
8
+ t.string :secret_key
9
+ t.datetime :delete_at
10
+
11
+ t.timestamps
12
+ end
13
+
14
+ create_table :loggable_activity_activities do |t|
15
+ t.string :action
16
+ t.references :actor, polymorphic: true, null: true
17
+ t.string :encrypted_actor_name
18
+ t.references :record, polymorphic: true, null: true
19
+
20
+ t.timestamps
21
+ end
22
+
23
+ create_table :loggable_activity_payloads do |t|
24
+ t.references :activity, null: false, foreign_key: { to_table: 'loggable_activity_activities' }
25
+ t.references :encryption_key, null: false, foreign_key: { to_table: 'loggable_activity_encryption_keys' }
26
+ t.references :record, polymorphic: true, null: true, index: true
27
+ t.string :encrypted_record_name
28
+ t.json :encrypted_attrs
29
+ t.integer :related_to_activity_as, default: 0
30
+ t.boolean :data_owner, default: false
31
+ t.string :route
32
+ t.boolean :current_payload, default: true
33
+ t.json :public_attrs, default: {}
34
+
35
+ t.timestamps
36
+ end
37
+
38
+ create_table :loggable_activity_data_owners do |t|
39
+ t.references :record, polymorphic: true, null: true, index: true
40
+ t.references :encryption_key, null: false, foreign_key: { to_table: 'loggable_activity_encryption_keys' }
41
+
42
+ t.timestamps
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,32 @@
1
+
2
+ # This file was generated when you installed Loggable Activity and is used for internationalization.
3
+ # When a model 'includes LoggableActivity::Hooks' tags for translations are generated.
4
+ # Example:
5
+ # class User < ApplicationRecord
6
+ # include LoggableActivity::Hooks
7
+ # end
8
+ # This will make the following tags for translations available:
9
+ # - loggable_activity.user.create
10
+ # - loggable_activity.user.show
11
+ # - loggable_activity.user.update
12
+ # - loggable_activity.user.destroy
13
+ # - loggable_activity.user.login
14
+ # - loggable_activity.user.logout
15
+ #
16
+ en:
17
+ loggable_activity:
18
+ activity:
19
+ actor: Actor
20
+ action: Action
21
+ record: Record
22
+ created_at: Created at
23
+ deleted: "*** DELETED ***"
24
+ user:
25
+ update: A user was updated
26
+ create: A user was created
27
+ show: "A user was shown"
28
+ destroy: A user was deleted
29
+ sign_up: A user signed up
30
+ login: A user logged in
31
+ logout: A user logged out
32
+
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This configuration file is for setting up the LoggableActivity gem in your Rails application.
4
+
5
+ # Specify the name of the model that represents the actor performing the activities.
6
+ # This should be a string that matches the class name of the model.
7
+ # Example: If your user model is named "User", set it to 'User'.
8
+ LoggableActivity.actor_model_name = 'User'
9
+
10
+ # Specify the attribute from which to fetch the actor's name.
11
+ # This should be eighter a string representing the attribute name of the actor model
12
+ # or a method that returns the actor's name.
13
+ # Example: If you want to use the user's email as their name, set it to 'email'.
14
+ LoggableActivity.fetch_actor_name_from = 'email'
15
+
16
+ # Specify the path to the configuration file for LoggableActivity.
17
+ # This file should be a YAML file that contains the necessary configuration for logging activities.
18
+ # The path is set relative to the Rails root directory.
19
+ # Example: The default configuration file path is 'config/loggable_activity.yaml'.
20
+ LoggableActivity.config_file_path = Rails.root.join('config/loggable_activity.yaml')
21
+
22
+ # Specify whether the sanitazion should be performed by a task or not
23
+ # If set to 'false' the sanitization is performed immediately.
24
+ # If set to 'true' the data is inaccessible, but can be restored.
25
+ # If set to 'true' you have to permanently delete
26
+ # the data by calling 'LoggableActivity::Sanitizer.run' from a task.
27
+ LoggableActivity.task_for_sanitization = false
@@ -0,0 +1,103 @@
1
+ Company:
2
+ fetch_record_name_from: name
3
+ route: /companies/:id
4
+ loggable_attrs:
5
+ - name
6
+ public_attrs:
7
+ - name
8
+ relations:
9
+ - has_many: :users
10
+ route: /users/:id
11
+ model: User
12
+ loggable_attrs:
13
+ - first_name
14
+ - last_name
15
+ auto_log:
16
+ - create
17
+ - update
18
+ - destroy
19
+ Hat:
20
+ fetch_record_name_from: color
21
+ route: /user/:id
22
+ loggable_attrs:
23
+ - color
24
+ auto_log:
25
+ - create
26
+ - destroy
27
+ relations:
28
+ - belongs_to: :user
29
+ route: /demo/users/:id
30
+ model: User
31
+ loggable_attrs:
32
+ - first_name
33
+ User:
34
+ fetch_record_name_from: full_name
35
+ route: /demo/users/:id
36
+ loggable_attrs:
37
+ - first_name
38
+ - last_name
39
+ - age
40
+ - email
41
+ - user_type
42
+ auto_log:
43
+ - create
44
+ - update
45
+ - destroy
46
+ public_attrs:
47
+ - age
48
+ - user_type
49
+ relations:
50
+ - has_one: :profile
51
+ route: /demo/users/:id/profile
52
+ model: Profile
53
+ loggable_attrs:
54
+ - bio
55
+ - phone_number
56
+ public_attrs:
57
+ - date_of_birth
58
+ - has_many: :hats
59
+ route: /users/:id
60
+ model: Hat
61
+ loggable_attrs:
62
+ - color
63
+ - belongs_to: :company
64
+ route: /companies/:id
65
+ model: Company
66
+ loggable_attrs:
67
+ - name
68
+ Profile:
69
+ fetch_record_name_from: phone_number
70
+ route: /demo/profiles/:id
71
+ loggable_attrs:
72
+ - bio
73
+ - profile_picture_url
74
+ - location
75
+ - date_of_birth
76
+ - phone_number
77
+ public_attrs:
78
+ - date_of_birth
79
+ # auto_log:
80
+ # - create
81
+ # - update
82
+ # - destroy
83
+ # relations:
84
+ # - belongs_to: :user
85
+ # route: /demo/users/:id
86
+ # model: User
87
+ # loggable_attrs:
88
+ # - first_name
89
+ # - last_name
90
+ # - age
91
+ # - email
92
+ # - user_type
93
+ # - belongs_to: :demo_address
94
+ # route: show_demo_address
95
+ # model: Demo::Address
96
+ # loggable_attrs:
97
+ # - street
98
+ # - postal_code
99
+ # - belongs_to: :demo_club
100
+ # route: show_demo_club
101
+ # model: Demo::Club
102
+ # loggable_attrs:
103
+ # - name
@@ -31,7 +31,8 @@ module LoggableActivity
31
31
  'has_many_update_payload' => 'has_many',
32
32
  'belongs_to_payload' => 'belongs_to',
33
33
  'belongs_to_destroy_payload' => 'belongs_to',
34
- 'belongs_to_update_payload' => 'belongs_to'
34
+ 'belongs_to_update_payload' => 'belongs_to',
35
+ 'custom_payload' => 'self'
35
36
  }.freeze
36
37
 
37
38
  # Returns an array of hashes, each representing an activity's attributes and its associated relations. The structure and relations to include are specified in 'config/loggable_activity.yaml'. This format is designed for UI display purposes.
@@ -106,7 +107,7 @@ module LoggableActivity
106
107
  # "David Bowie"
107
108
  #
108
109
  def record_display_name
109
- primary_payload.record_display_name
110
+ primary_payload&.record_display_name
110
111
  end
111
112
 
112
113
  # Returns the path for the activity.
@@ -135,7 +136,6 @@ module LoggableActivity
135
136
  return I18n.t('loggable.activity.deleted') if actor_deleted?
136
137
 
137
138
  ::LoggableActivity::Encryption.decrypt(encrypted_actor_name, actor_secret_key)
138
-
139
139
  end
140
140
 
141
141
  # Returns a list of activities for a given actor.
@@ -172,7 +172,7 @@ module LoggableActivity
172
172
  # payload.record_type # => 'SOMD_MODEL_NAME'
173
173
  #
174
174
  def primary_payload
175
- related_to_activity_as = %w[primary_payload primary_update_payload primary_destroy_payload]
175
+ related_to_activity_as = %w[primary_payload primary_update_payload primary_destroy_payload custom_payload]
176
176
  payloads.detect { |p| related_to_activity_as.include?(p.related_to_activity_as) }
177
177
  end
178
178
 
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LoggableActivity
4
+ # Stores current user in a thread variable so is can be accessed from the LoggableActivity::Hook model
5
+ module CurrentActor
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ before_action :set_current_actor
10
+ after_action :clear_current_actor
11
+ end
12
+
13
+ private
14
+
15
+ def set_current_actor
16
+ return unless current_user
17
+
18
+ Thread.current[:current_actor] = current_user
19
+ end
20
+
21
+ def clear_current_actor
22
+ Thread.current[:current_actor] = nil
23
+ end
24
+ end
25
+ end
@@ -1,16 +1,8 @@
1
1
  {
2
2
  "$schema": "http://json-schema.org/draft-06/schema#",
3
3
  "type": "object",
4
- "properties": {
5
- "fetch_actor_name_from": {
6
- "type": "string"
7
- },
8
- "task_for_sanitization": {
9
- "type": "boolean"
10
- }
11
- },
12
4
  "patternProperties": {
13
- "^(?!fetch_actor_name_from$|task_for_sanitization)[A-Za-z0-9_:]+$": {
5
+ "^[A-Za-z0-9_:]+$": {
14
6
  "type": "object",
15
7
  "properties": {
16
8
  "data_owner": {
@@ -82,8 +74,5 @@
82
74
  ]
83
75
  }
84
76
  },
85
- "additionalProperties": false,
86
- "required": [
87
- "fetch_actor_name_from"
88
- ]
77
+ "additionalProperties": false
89
78
  }
@@ -51,16 +51,6 @@ module LoggableActivity
51
51
  def for_class(class_name)
52
52
  config_data[class_name]
53
53
  end
54
-
55
- # Returns the name of the field or method to use for the actor's display name.
56
- def fetch_actor_name_from
57
- config_data['fetch_actor_name_from']
58
- end
59
-
60
- # Returns whatever models should be sanitized on delete.
61
- def task_for_sanitization
62
- config_data['task_for_sanitization']
63
- end
64
54
  end
65
55
  end
66
56
  end
@@ -16,13 +16,11 @@ module LoggableActivity
16
16
  # "SOME_ENCRYPTED_STRING"
17
17
  #
18
18
  def self.encrypt(data, secret_key)
19
- return nil if secret_key.nil?
20
- return nil if data.nil?
19
+ return nil if secret_key.nil? || data.nil?
21
20
 
22
21
  encryption_key = Base64.decode64(secret_key)
23
22
  unless encryption_key.bytesize == 32
24
- raise EncryptionError,
25
- "Encryption failed: Invalid encoded_key length #{encryption_key.bytesize}"
23
+ raise EncryptionError, "Encryption failed: Invalid encoded_key length #{encryption_key.bytesize}"
26
24
  end
27
25
 
28
26
  cipher = OpenSSL::Cipher.new('AES-256-CBC').encrypt
@@ -39,19 +37,47 @@ module LoggableActivity
39
37
  # Decrypts the given data using the given encryption key
40
38
  #
41
39
  # Example:
42
- # ::LoggableActivity::Encryption.decrypt('SOME_ENCRYPTED_STRING', 'SECRET_KEY')
40
+ # ::LoggableActivity::Encryption.decrypt('SOME_ENCRYPTED_DATA', 'SECRET_KEY')
43
41
  #
44
42
  # Returns:
45
43
  # "my secret data"
46
44
  #
47
45
  def self.decrypt(data, secret_key)
46
+ case data
47
+ when Hash
48
+ decrypt_hash(data, secret_key)
49
+ when Array
50
+ decrypt_array(data, secret_key)
51
+ else
52
+ decrypt_data(data, secret_key)
53
+ end
54
+ end
55
+
56
+ # Decrypts a hash's values using the given encryption key
57
+ def self.decrypt_hash(data, secret_key)
58
+ data
59
+ .transform_values { |value| decrypt(value, secret_key) }
60
+ .transform_keys(&:to_sym)
61
+ end
62
+
63
+ # Decrypts an array's values using the given encryption key
64
+ def self.decrypt_array(data, secret_key)
65
+ data.map { |value| decrypt(value, secret_key) }
66
+ end
67
+
68
+ # Checks if a value is blank
69
+ def self.blank?(value)
70
+ value.respond_to?(:empty?) ? value.empty? : !value
71
+ end
72
+
73
+ # Decrypts individual data using the given encryption key
74
+ def self.decrypt_data(data, secret_key)
48
75
  return I18n.t('loggable_activity.activity.deleted') if secret_key.nil?
49
76
  return '' if data.blank?
50
77
 
51
78
  encryption_key = Base64.decode64(secret_key)
52
79
  unless encryption_key.bytesize == 32
53
- raise EncryptionError,
54
- "Decryption failed: Invalid encoded_key length: #{encryption_key.bytesize}"
80
+ raise EncryptionError, "Decryption failed: Invalid encoded_key length: #{encryption_key.bytesize}"
55
81
  end
56
82
 
57
83
  cipher = OpenSSL::Cipher.new('AES-256-CBC').decrypt
@@ -73,10 +99,5 @@ module LoggableActivity
73
99
  Rails.logger.error "ArgumentError Decryption failed: #{e.message}"
74
100
  I18n.t('loggable_activity.decryption.failed')
75
101
  end
76
-
77
- # Returns true if the given value is blank
78
- def self.blank?(value)
79
- value.respond_to?(:empty?) ? value.empty? : !value
80
- end
81
102
  end
82
103
  end
@@ -14,7 +14,7 @@ module LoggableActivity
14
14
 
15
15
  # Prepare the record for deletion
16
16
  def mark_as_deleted!
17
- LoggableActivity::Configuration.task_for_sanitization ? update(delete_at: DateTime.now + 1.month) : delete
17
+ LoggableActivity.task_for_sanitization ? update(delete_at: DateTime.now + 1.month) : delete
18
18
  end
19
19
 
20
20
  # check if the encryption key is deleted or it is about to be deleted
@@ -4,21 +4,21 @@ module LoggableActivity
4
4
  # Error class for loggable activity.
5
5
  class Error < StandardError
6
6
  def initialize(msg = '')
7
- super(msg)
7
+ super
8
8
  end
9
9
  end
10
10
 
11
11
  # Error class for encryption.
12
12
  class EncryptionError < StandardError
13
13
  def initialize(msg = '')
14
- super(msg)
14
+ super
15
15
  end
16
16
  end
17
17
 
18
18
  # This class is used to load the configuration file located at config/loggable_activity.yml
19
19
  class ConfigurationError < StandardError
20
20
  def initialize(msg = '')
21
- super(msg)
21
+ super
22
22
  end
23
23
  end
24
24
  end
@@ -18,17 +18,17 @@ module LoggableActivity
18
18
  included do
19
19
  config = ::LoggableActivity::Configuration.for_class(name)
20
20
 
21
- if config.nil?
22
- raise LoggableActivity::Error, "Configuration not found for #{name}, Please add it to 'config/loggable_activity.yaml"
23
- end
24
-
21
+ # if config.nil?
22
+ # # logg all attributes by default.
23
+ # self.loggable_attrs = attribute_names
24
+ # end
25
25
  # Initializes attributes based on configuration.
26
- self.loggable_attrs = config&.fetch('loggable_attrs', []) || []
26
+ self.loggable_attrs = config&.fetch('loggable_attrs', []) || attribute_names
27
27
  self.public_attrs = config&.fetch('public_attrs', []) || []
28
28
  self.relations = config&.fetch('relations', []) || []
29
- self.auto_log = config&.fetch('auto_log', []) || []
30
- self.fetch_record_name_from = config&.fetch('fetch_record_name_from', nil)
29
+ self.auto_log = config&.fetch('auto_log', []) || %w[create update destroy]
31
30
  self.route = config&.fetch('route', nil)
31
+ self.fetch_record_name_from = config&.fetch('fetch_record_name_from', nil)
32
32
 
33
33
  after_create :log_create_activity
34
34
  after_update :log_update_activity
@@ -42,7 +42,7 @@ module LoggableActivity
42
42
  # @param params [Hash] Additional parameters for the activity.
43
43
  def log(action, actor: nil, params: {})
44
44
  @action = action
45
- @actor = actor || Thread.current[:current_user]
45
+ @actor = actor || Thread.current[:current_actor]
46
46
  return nil if @actor.nil?
47
47
 
48
48
  @record = self
@@ -50,14 +50,22 @@ module LoggableActivity
50
50
  @payloads = []
51
51
 
52
52
  case action
53
- when :create, :show
54
- log_activity
53
+ when :create
54
+ log_create
55
+ when :show
56
+ log_show
55
57
  when :destroy
56
58
  log_destroy
57
59
  when :update
58
60
  log_update
61
+ when :login
62
+ log_login
63
+ when :logout
64
+ log_logout
65
+ when :sign_up
66
+ log_sign_up
59
67
  else
60
- log_custom_activity(action)
68
+ log_custom_activity
61
69
  end
62
70
  end
63
71
 
@@ -67,9 +75,17 @@ module LoggableActivity
67
75
 
68
76
  private
69
77
 
70
- # Logs an activity for the current action.
71
- def log_activity
72
- create_activity(build_payloads)
78
+ # Logs an activity for the show action.
79
+ def log_show
80
+ return nil if just_created?
81
+ return nil if just_updated?
82
+
83
+ log_activity
84
+ end
85
+
86
+ # Logs an activity for the create action.
87
+ def log_create
88
+ log_activity
73
89
  end
74
90
 
75
91
  # Logs an activity for the update action.
@@ -82,6 +98,27 @@ module LoggableActivity
82
98
  create_activity(build_destroy_payload)
83
99
  end
84
100
 
101
+ # Logs an activity for the current action.
102
+ def log_activity
103
+ create_activity(build_payloads)
104
+ end
105
+
106
+ def just_created?
107
+ action = "#{self.class.base_action}.create"
108
+ activity = LoggableActivity::Activity.where(record: self, actor: @actor).last
109
+ return false unless activity && activity.action == action && activity.created_at > 5.seconds.ago
110
+
111
+ true
112
+ end
113
+
114
+ def just_updated?
115
+ action = "#{self.class.base_action}.update"
116
+ activity = LoggableActivity::Activity.where(record: self, actor: @actor).last
117
+ return false unless activity && activity.action == action && activity.created_at > 5.seconds.ago
118
+
119
+ true
120
+ end
121
+
85
122
  # Creates an activity with the specified payloads.
86
123
  def create_activity(payloads)
87
124
  return nil if nothing_to_log?(payloads)
@@ -95,6 +132,28 @@ module LoggableActivity
95
132
  )
96
133
  end
97
134
 
135
+ def log_login
136
+ create_activity(build_payloads)
137
+ end
138
+
139
+ def log_logout
140
+ create_activity(build_payloads)
141
+ end
142
+
143
+ def log_sign_up
144
+ create_activity(build_payloads)
145
+ end
146
+
147
+ # Logs a custom activity.
148
+ def log_custom_activity
149
+ create_activity(build_custom_payload)
150
+ end
151
+
152
+ def build_custom_payload
153
+ ::LoggableActivity::Services::CustomPayloadsBuilder
154
+ .new(self, @payloads, @params).build
155
+ end
156
+
98
157
  # Builds update payloads for the current action.
99
158
  def build_update_payloads
100
159
  ::LoggableActivity::Services::UpdatePayloadsBuilder
@@ -118,9 +177,6 @@ module LoggableActivity
118
177
  @payloads.empty?
119
178
  end
120
179
 
121
- # Logs a custom activity.
122
- def log_custom_activity(activity); end
123
-
124
180
  # Logs an update activity automatically if configured.
125
181
  def log_update_activity
126
182
  return unless hooks_enabled?
@@ -171,7 +227,7 @@ module LoggableActivity
171
227
 
172
228
  # Reads the field to feetch the record name from.
173
229
  def fetch_actor_name_from
174
- ::LoggableActivity::Configuration.fetch_actor_name_from
230
+ LoggableActivity.fetch_actor_name_from
175
231
  end
176
232
 
177
233
  # Returns the action key for the current action.
@@ -22,6 +22,7 @@ module LoggableActivity
22
22
  has_one_payload
23
23
  belongs_to_update_payload
24
24
  has_many_create_payload
25
+ custom_payload
25
26
  ].freeze
26
27
 
27
28
  # Enumeration for different updatepayload types
@@ -47,7 +48,8 @@ module LoggableActivity
47
48
  belongs_to_update_payload: 9,
48
49
  belongs_to_destroy_payload: 10,
49
50
  has_one_destroy_payload: 11,
50
- has_many_destroy_payload: 12
51
+ has_many_destroy_payload: 12,
52
+ custom_payload: 13
51
53
  }
52
54
 
53
55
  # Returns the decrypted attrs.
@@ -62,14 +64,14 @@ module LoggableActivity
62
64
  #
63
65
  def attrs
64
66
  return deleted_attrs if record.nil?
65
-
67
+
66
68
  case related_to_activity_as
67
69
  when *DECRYPT_ATTRS_TYPES
68
- decrypted_attrs.merge(public_attrs: public_attrs)
70
+ decrypted_attrs.merge(public_attrs:)
69
71
  when *DECRYPT_UPDATE_ATTRS_TYPES
70
72
  decrypted_update_attrs + public_attrs['changes']
71
73
  else
72
- { public_attrs: public_attrs }
74
+ { public_attrs: }
73
75
  end
74
76
  end
75
77