loggable_activity 0.1.39 → 0.1.42

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. checksums.yaml +4 -4
  2. data/.document +1 -0
  3. data/.nojekyll +1 -0
  4. data/.rubocop.yml +1 -1
  5. data/doc/.nojekyll +1 -0
  6. data/doc/CHANGELOG_md.html +125 -0
  7. data/doc/CODE_OF_CONDUCT_md.html +220 -0
  8. data/doc/CONSIDERTIONS_md.html +227 -0
  9. data/doc/CreateLoggableActivities.html +144 -0
  10. data/doc/CreateLoggableEncryptionKeys.html +140 -0
  11. data/doc/CreateLoggablePayloads.html +144 -0
  12. data/doc/GETTING-STARTED_md.html +186 -0
  13. data/doc/Gemfile.html +104 -0
  14. data/doc/Gemfile_lock.html +152 -0
  15. data/doc/LICENSE_txt.html +104 -0
  16. data/doc/LoggableActivity/CurrentUser.html +99 -0
  17. data/doc/LoggableActivity/Generators/InstallGenerator.html +178 -0
  18. data/doc/LoggableActivity/Generators.html +91 -0
  19. data/doc/README_md.html +138 -0
  20. data/doc/ROADMAP_md.html +151 -0
  21. data/doc/Rakefile.html +102 -0
  22. data/doc/bin/setup.html +100 -0
  23. data/doc/notes/CHEAT_SHEET_md.html +130 -0
  24. data/doc/sig/loggable_activity_rbs.html +101 -0
  25. data/docs/LoggableActivity/Activity.html +494 -0
  26. data/docs/LoggableActivity/Configuration.html +183 -0
  27. data/docs/LoggableActivity/Encryption.html +220 -0
  28. data/docs/LoggableActivity/EncryptionError.html +99 -0
  29. data/docs/LoggableActivity/EncryptionKey.html +327 -0
  30. data/docs/LoggableActivity/Error.html +97 -0
  31. data/docs/LoggableActivity/Hooks.html +172 -0
  32. data/docs/LoggableActivity/Payload.html +159 -0
  33. data/docs/LoggableActivity/PayloadsBuilder.html +154 -0
  34. data/docs/LoggableActivity/UpdatePayloadsBuilder.html +199 -0
  35. data/docs/LoggableActivity.html +100 -0
  36. data/docs/created.rid +10 -0
  37. data/docs/css/fonts.css +167 -0
  38. data/docs/css/rdoc.css +687 -0
  39. data/docs/fonts/Lato-Light.ttf +0 -0
  40. data/docs/fonts/Lato-LightItalic.ttf +0 -0
  41. data/docs/fonts/Lato-Regular.ttf +0 -0
  42. data/docs/fonts/Lato-RegularItalic.ttf +0 -0
  43. data/docs/fonts/SourceCodePro-Bold.ttf +0 -0
  44. data/docs/fonts/SourceCodePro-Regular.ttf +0 -0
  45. data/docs/images/add.png +0 -0
  46. data/docs/images/arrow_up.png +0 -0
  47. data/docs/images/brick.png +0 -0
  48. data/docs/images/brick_link.png +0 -0
  49. data/docs/images/bug.png +0 -0
  50. data/docs/images/bullet_black.png +0 -0
  51. data/docs/images/bullet_toggle_minus.png +0 -0
  52. data/docs/images/bullet_toggle_plus.png +0 -0
  53. data/docs/images/date.png +0 -0
  54. data/docs/images/delete.png +0 -0
  55. data/docs/images/find.png +0 -0
  56. data/docs/images/loadingAnimation.gif +0 -0
  57. data/docs/images/macFFBgHack.png +0 -0
  58. data/docs/images/package.png +0 -0
  59. data/docs/images/page_green.png +0 -0
  60. data/docs/images/page_white_text.png +0 -0
  61. data/docs/images/page_white_width.png +0 -0
  62. data/docs/images/plugin.png +0 -0
  63. data/docs/images/ruby.png +0 -0
  64. data/docs/images/tag_blue.png +0 -0
  65. data/docs/images/tag_green.png +0 -0
  66. data/docs/images/transparent.png +0 -0
  67. data/docs/images/wrench.png +0 -0
  68. data/docs/images/wrench_orange.png +0 -0
  69. data/docs/images/zoom.png +0 -0
  70. data/docs/index.html +91 -0
  71. data/docs/js/darkfish.js +97 -0
  72. data/docs/js/navigation.js +105 -0
  73. data/docs/js/navigation.js.gz +0 -0
  74. data/docs/js/search.js +110 -0
  75. data/docs/js/search_index.js +1 -0
  76. data/docs/js/search_index.js.gz +0 -0
  77. data/docs/js/searcher.js +229 -0
  78. data/docs/js/searcher.js.gz +0 -0
  79. data/docs/table_of_contents.html +184 -0
  80. data/lib/generators/loggable_activity/install_generator.rb +2 -1
  81. data/lib/generators/loggable_activity/templates/current_user.rb +1 -1
  82. data/lib/generators/loggable_activity/templates/loggable_activity.yml +29 -0
  83. data/lib/loggable_activity/activity.rb +208 -59
  84. data/lib/loggable_activity/configuration.rb +18 -0
  85. data/lib/loggable_activity/encryption.rb +20 -1
  86. data/lib/loggable_activity/encryption_key.rb +81 -14
  87. data/lib/loggable_activity/hooks.rb +10 -7
  88. data/lib/loggable_activity/payload.rb +45 -11
  89. data/lib/loggable_activity/payloads_builder.rb +50 -4
  90. data/lib/loggable_activity/update_payloads_builder.rb +64 -2
  91. data/lib/loggable_activity/version.rb +1 -1
  92. metadata +81 -9
  93. data/.DS_Store +0 -0
  94. data/loggable_activity-0.1.32.gem +0 -0
  95. data/loggable_activity-0.1.33.gem +0 -0
  96. data/loggable_activity-0.1.34.gem +0 -0
Binary file
@@ -0,0 +1,184 @@
1
+ <!DOCTYPE html>
2
+
3
+ <html>
4
+ <head>
5
+ <meta charset="UTF-8">
6
+
7
+ <title>Table of Contents - RDoc Documentation</title>
8
+
9
+ <script type="text/javascript">
10
+ var rdoc_rel_prefix = "./";
11
+ var index_rel_prefix = "./";
12
+ </script>
13
+
14
+ <script src="./js/navigation.js" defer></script>
15
+ <script src="./js/search.js" defer></script>
16
+ <script src="./js/search_index.js" defer></script>
17
+ <script src="./js/searcher.js" defer></script>
18
+ <script src="./js/darkfish.js" defer></script>
19
+
20
+ <link href="./css/fonts.css" rel="stylesheet">
21
+ <link href="./css/rdoc.css" rel="stylesheet">
22
+
23
+
24
+ <body id="top" class="table-of-contents">
25
+ <main role="main">
26
+ <h1 class="class">Table of Contents - RDoc Documentation</h1>
27
+
28
+
29
+ <h2 id="classes">Classes and Modules</h2>
30
+ <ul>
31
+ <li class="module">
32
+ <a href="LoggableActivity.html">LoggableActivity</a>
33
+ </li>
34
+ <li class="class">
35
+ <a href="LoggableActivity/Activity.html">LoggableActivity::Activity</a>
36
+ </li>
37
+ <li class="class">
38
+ <a href="LoggableActivity/Configuration.html">LoggableActivity::Configuration</a>
39
+ </li>
40
+ <li class="module">
41
+ <a href="LoggableActivity/Encryption.html">LoggableActivity::Encryption</a>
42
+ </li>
43
+ <li class="class">
44
+ <a href="LoggableActivity/EncryptionError.html">LoggableActivity::EncryptionError</a>
45
+ </li>
46
+ <li class="class">
47
+ <a href="LoggableActivity/EncryptionKey.html">LoggableActivity::EncryptionKey</a>
48
+ </li>
49
+ <li class="module">
50
+ <a href="LoggableActivity/Hooks.html">LoggableActivity::Hooks</a>
51
+ </li>
52
+ <li class="class">
53
+ <a href="LoggableActivity/Payload.html">LoggableActivity::Payload</a>
54
+ </li>
55
+ <li class="module">
56
+ <a href="LoggableActivity/PayloadsBuilder.html">LoggableActivity::PayloadsBuilder</a>
57
+ </li>
58
+ <li class="module">
59
+ <a href="LoggableActivity/UpdatePayloadsBuilder.html">LoggableActivity::UpdatePayloadsBuilder</a>
60
+ </li>
61
+ </ul>
62
+
63
+ <h2 id="methods">Methods</h2>
64
+ <ul>
65
+
66
+ <li class="method">
67
+ <a href="LoggableActivity/Activity.html#method-c-activities_for_actor">::activities_for_actor</a>
68
+ &mdash;
69
+ <span class="container">LoggableActivity::Activity</span>
70
+
71
+ <li class="method">
72
+ <a href="LoggableActivity/Encryption.html#method-c-blank-3F">::blank?</a>
73
+ &mdash;
74
+ <span class="container">LoggableActivity::Encryption</span>
75
+
76
+ <li class="method">
77
+ <a href="LoggableActivity/EncryptionKey.html#method-c-create_encryption_key">::create_encryption_key</a>
78
+ &mdash;
79
+ <span class="container">LoggableActivity::EncryptionKey</span>
80
+
81
+ <li class="method">
82
+ <a href="LoggableActivity/Encryption.html#method-c-decrypt">::decrypt</a>
83
+ &mdash;
84
+ <span class="container">LoggableActivity::Encryption</span>
85
+
86
+ <li class="method">
87
+ <a href="LoggableActivity/Encryption.html#method-c-encrypt">::encrypt</a>
88
+ &mdash;
89
+ <span class="container">LoggableActivity::Encryption</span>
90
+
91
+ <li class="method">
92
+ <a href="LoggableActivity/Configuration.html#method-c-for_class">::for_class</a>
93
+ &mdash;
94
+ <span class="container">LoggableActivity::Configuration</span>
95
+
96
+ <li class="method">
97
+ <a href="LoggableActivity/EncryptionKey.html#method-c-for_record">::for_record</a>
98
+ &mdash;
99
+ <span class="container">LoggableActivity::EncryptionKey</span>
100
+
101
+ <li class="method">
102
+ <a href="LoggableActivity/EncryptionKey.html#method-c-for_record_by_type_and_id">::for_record_by_type_and_id</a>
103
+ &mdash;
104
+ <span class="container">LoggableActivity::EncryptionKey</span>
105
+
106
+ <li class="method">
107
+ <a href="LoggableActivity/Activity.html#method-c-latest">::latest</a>
108
+ &mdash;
109
+ <span class="container">LoggableActivity::Activity</span>
110
+
111
+ <li class="method">
112
+ <a href="LoggableActivity/Configuration.html#method-c-load_config_file">::load_config_file</a>
113
+ &mdash;
114
+ <span class="container">LoggableActivity::Configuration</span>
115
+
116
+ <li class="method">
117
+ <a href="LoggableActivity/EncryptionKey.html#method-c-random_key">::random_key</a>
118
+ &mdash;
119
+ <span class="container">LoggableActivity::EncryptionKey</span>
120
+
121
+ <li class="method">
122
+ <a href="LoggableActivity/Activity.html#method-i-actor_display_name">#actor_display_name</a>
123
+ &mdash;
124
+ <span class="container">LoggableActivity::Activity</span>
125
+
126
+ <li class="method">
127
+ <a href="LoggableActivity/Activity.html#method-i-attrs">#attrs</a>
128
+ &mdash;
129
+ <span class="container">LoggableActivity::Activity</span>
130
+
131
+ <li class="method">
132
+ <a href="LoggableActivity/Payload.html#method-i-attrs">#attrs</a>
133
+ &mdash;
134
+ <span class="container">LoggableActivity::Payload</span>
135
+
136
+ <li class="method">
137
+ <a href="LoggableActivity/PayloadsBuilder.html#method-i-build_payloads">#build_payloads</a>
138
+ &mdash;
139
+ <span class="container">LoggableActivity::PayloadsBuilder</span>
140
+
141
+ <li class="method">
142
+ <a href="LoggableActivity/UpdatePayloadsBuilder.html#method-i-build_update_payloads">#build_update_payloads</a>
143
+ &mdash;
144
+ <span class="container">LoggableActivity::UpdatePayloadsBuilder</span>
145
+
146
+ <li class="method">
147
+ <a href="LoggableActivity/Hooks.html#method-i-log">#log</a>
148
+ &mdash;
149
+ <span class="container">LoggableActivity::Hooks</span>
150
+
151
+ <li class="method">
152
+ <a href="LoggableActivity/EncryptionKey.html#method-i-mark_as_deleted">#mark_as_deleted</a>
153
+ &mdash;
154
+ <span class="container">LoggableActivity::EncryptionKey</span>
155
+
156
+ <li class="method">
157
+ <a href="LoggableActivity/Activity.html#method-i-primary_payload_attrs">#primary_payload_attrs</a>
158
+ &mdash;
159
+ <span class="container">LoggableActivity::Activity</span>
160
+
161
+ <li class="method">
162
+ <a href="LoggableActivity/Activity.html#method-i-record_display_name">#record_display_name</a>
163
+ &mdash;
164
+ <span class="container">LoggableActivity::Activity</span>
165
+
166
+ <li class="method">
167
+ <a href="LoggableActivity/Activity.html#method-i-relations_attrs">#relations_attrs</a>
168
+ &mdash;
169
+ <span class="container">LoggableActivity::Activity</span>
170
+
171
+ <li class="method">
172
+ <a href="LoggableActivity/Activity.html#method-i-update_activity_attrs">#update_activity_attrs</a>
173
+ &mdash;
174
+ <span class="container">LoggableActivity::Activity</span>
175
+ </ul>
176
+ </main>
177
+
178
+
179
+ <footer id="validator-badges" role="contentinfo">
180
+ <p><a href="https://validator.w3.org/check/referer">Validate</a>
181
+ <p>Generated by <a href="https://ruby.github.io/rdoc/">RDoc</a> 6.6.2.
182
+ <p>Based on <a href="http://deveiate.org/projects/Darkfish-RDoc/">Darkfish</a> by <a href="http://deveiate.org">Michael Granger</a>.
183
+ </footer>
184
+
@@ -23,7 +23,8 @@ module LoggableActivity
23
23
 
24
24
  def create_model_file
25
25
  template 'loggable_activity.en.yml', 'config/locales/loggable_activity.en.yml'
26
- template "current_user.rb", 'app/controllers/concerns/loggable_activity/current_user.rb'
26
+ template 'loggable_activity.yml', 'config/loggable_activity.yml'
27
+ template 'current_user.rb', 'app/controllers/concerns/loggable_activity/current_user.rb'
27
28
  end
28
29
  end
29
30
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Stores current user in a thread variable so that is can be accessed from the 'models/conserns/loggable/activities.rb' file.
4
3
  module LoggableActivity
4
+ # Stores current user in a thread variable so is can be accessed from the LoggableActivity::Hook model
5
5
  module CurrentUser
6
6
  extend ActiveSupport::Concern
7
7
 
@@ -0,0 +1,29 @@
1
+ # User:
2
+ # record_display_name: full_name
3
+ # loggable_attrs:
4
+ # - first_name
5
+ # - last_name
6
+ # - age
7
+ # - email
8
+ # - user_type
9
+ # auto_log:
10
+ # - create
11
+ # - update
12
+ # - destroy
13
+ # relations:
14
+ # - has_one: :demo_user_profile
15
+ # model: Demo::UserProfile
16
+ # loggable_attrs:
17
+ # - sex
18
+ # - religion
19
+ # - belongs_to: :demo_address
20
+ # model: Demo::Address
21
+ # loggable_attrs:
22
+ # - street
23
+ # - city
24
+ # - country
25
+ # - postal_code
26
+ # - belongs_to: :demo_club
27
+ # model: Demo::Club
28
+ # loggable_attrs:
29
+ # - name
@@ -1,29 +1,132 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # This is the activity log. It contains an agregation of payloads.
4
- # It reprecent one activity for the log
5
-
6
3
  module LoggableActivity
4
+ # Represents one action in the activity log.
7
5
  class Activity < ActiveRecord::Base
8
6
  self.table_name = 'loggable_activities'
7
+ # Associations
9
8
  has_many :payloads, class_name: 'LoggableActivity::Payload', dependent: :destroy
9
+ belongs_to :record, polymorphic: true, optional: true
10
+ belongs_to :actor, polymorphic: true, optional: true
11
+
10
12
  accepts_nested_attributes_for :payloads
11
13
 
14
+ # Validations
12
15
  validates :actor, presence: true
13
16
  validates :action, presence: true
14
- # validates :encrypted_record_display_name, presence: true
15
- # validates :encrypted_actor_display_name, presence: true
16
-
17
17
  validate :must_have_at_least_one_payload
18
18
 
19
- belongs_to :record, polymorphic: true, optional: true
20
- belongs_to :actor, polymorphic: true, optional: true
21
-
19
+ # Returns a list of attributes of the activity includig the indliced relations.
20
+ # The included relations are devined in the 'config/loggable_activity.yaml' file.
21
+ # The attributes are packed in a way that they can be used to display the activity in the UI.
22
+ #
23
+ # Example:
24
+ # @activity.attrs
25
+ #
26
+ # Returns:
27
+ # [
28
+ # {
29
+ # record_class: "User",
30
+ # payload_type: "primary_payload",
31
+ # attrs: {
32
+ # "first_name" => "David",
33
+ # "last_name" => "Bowie",
34
+ # "age" => "69",
35
+ # "email" => "david@example.com",
36
+ # "user_type" => "Patient"
37
+ # }
38
+ # },
39
+ # {
40
+ # record_class: "Demo::UserProfile",
41
+ # payload_type: "current_association",
42
+ # attrs: {
43
+ # "sex" => "Male",
44
+ # "religion" => "Agnostic"
45
+ # }
46
+ # },
47
+ # {
48
+ # record_class: "Demo::Address",
49
+ # payload_type: "current_association",
50
+ # attrs: {
51
+ # "street" => "Eiffel Tower",
52
+ # "city" => "Paris",
53
+ # "country" => "France",
54
+ # "postal_code" => "75007"
55
+ # }
56
+ # },
57
+ # {
58
+ # record_class: "Demo::Club",
59
+ # payload_type: "current_association",
60
+ # attrs: {
61
+ # "name" => "Mystic Fusion Lounge"
62
+ # }
63
+ # }
64
+ # ]
65
+ #
22
66
  def attrs
23
- # @attrs ||= payloads_attrs
24
- payloads_attrs
67
+ ordered_payloads.map do |payload|
68
+ {
69
+ record_class: payload.record_type,
70
+ payload_type: payload.payload_type,
71
+ attrs: payload.attrs
72
+ }
73
+ end
25
74
  end
26
75
 
76
+ # Returns the attributes of an upddate activity.
77
+ #
78
+ # Example:
79
+ # @activity.update_activity_attrs
80
+ #
81
+ # Returns:
82
+ # {
83
+ # # Update attributes for Demo::Club
84
+ # update_attrs: {
85
+ # record_class: "Demo::Club",
86
+ # attrs: [
87
+ # {
88
+ # "name" => {
89
+ # # Previous name
90
+ # from: "Electric Oasis Club",
91
+ # # New name
92
+ # to: "Electric Oasis Club nr 5"
93
+ # }
94
+ # }
95
+ # ]
96
+ # },
97
+ # # Updated relations attributes
98
+ # updated_relations_attrs: [
99
+ # {
100
+ # record_class: "Demo::Address",
101
+ # previous_attrs: {
102
+ # # Record class
103
+ # record_class: "Demo::Address",
104
+ # # Previous association payload type
105
+ # payload_type: "previous_association",
106
+ # # Previous attributes for Demo::Address
107
+ # attrs: {
108
+ # "street" => "Ice Hotel, Marknadsvägen 63",
109
+ # "city" => "Jukkasjärvi",
110
+ # "country" => "Sweden",
111
+ # "postal_code" => "981 91"
112
+ # }
113
+ # },
114
+ # current_attrs: {
115
+ # record_class: "Demo::Address",
116
+ # # Current association payload type
117
+ # payload_type: "current_association",
118
+ # # Current attributes for Demo::Address
119
+ # attrs: {
120
+ # "street" => "The Palace of Versailles",
121
+ # "city" => "Versailles",
122
+ # "country" => "France",
123
+ # "postal_code" => "78000"
124
+ # }
125
+ # }
126
+ # }
127
+ # ]
128
+ # }
129
+ #
27
130
  def update_activity_attrs
28
131
  {
29
132
  update_attrs:,
@@ -31,46 +134,98 @@ module LoggableActivity
31
134
  }
32
135
  end
33
136
 
137
+ # Returns the attributes for the primary payload, without the relations.
138
+ #
139
+ # Example:
140
+ #
141
+ # @activity.primary_payload_attrs
142
+ #
143
+ # Returns:
144
+ # {
145
+ # "first_name" => "David",
146
+ # "last_name" => "Bowie",
147
+ # "age" => "69",
148
+ # "email" => "david@example.com",
149
+ # "user_type" => "Patient"
150
+ # }
151
+ #
34
152
  def primary_payload_attrs
35
153
  primary_payload ? primary_payload.attrs : {}
36
154
  end
37
155
 
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' }
156
+ # Returns the attributes for the relations.
157
+ #
158
+ # Example:
159
+ #
160
+ # @activity.relations_attrs
161
+ #
162
+ # Returns:
163
+ # [
164
+ # {
165
+ # record_class: "Demo::Address",
166
+ # # Current association payload type
167
+ # payload_type: "current_association",
168
+ # # Current attributes for Demo::Address
169
+ # attrs: {
170
+ # "street" => "The Palace of Versailles",
171
+ # "city" => "Versailles",
172
+ # "country" => "France",
173
+ # "postal_code" => "78000"
174
+ # }
175
+ # }
176
+ # ]
177
+ def relations_attrs
178
+ attrs.filter { |p| p[:payload_type] == 'current_association' }
41
179
  end
42
180
 
43
- def ordered_payloads
44
- # @ordered_payloads ||= payloads.order(:payload_type)
45
- payloads.order(:payload_type)
46
- end
181
+ # Returns the display name for a record. what method to use if defined in '/config/loggable_activity.yaml'
182
+ #
183
+ # Example:
184
+ #
185
+ # @activity.record_display_name
186
+ #
187
+ # Returns:
188
+ # "David Bowie"
189
+ #
190
+ def record_display_name
191
+ return I18n.t('loggable.activity.deleted') if encrypted_record_display_name.nil?
47
192
 
48
- def relations_attrs
49
- attrs.filter { |p| p[:payload_type] == 'current_association' }
193
+ LoggableActivity::Encryption.decrypt(encrypted_record_display_name, record_key)
50
194
  end
51
195
 
52
- def updated_relations_attrs
53
- grouped_associations = attrs.group_by { |p| p[:record_class] }
196
+ # Returns the display name for a actor. what method to use if defined in '/config/loggable_activity.yaml'
197
+ #
198
+ # Example:
199
+ #
200
+ # @activity.actor_display_name
201
+ #
202
+ # Returns:
203
+ # "Elvis Presley"
204
+ #
205
+ def actor_display_name
206
+ return I18n.t('loggable.activity.deleted') if encrypted_actor_display_name.nil?
54
207
 
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?
208
+ LoggableActivity::Encryption.decrypt(encrypted_actor_display_name, actor_key)
209
+ end
59
210
 
60
- { record_class:, previous_attrs:, current_attrs: }
61
- end.compact
211
+ # Returns a list of activities for a given actor.
212
+ def self.activities_for_actor(actor, limit = 20, params = { offset: 0 })
213
+ LoggableActivity::Activity.latest(limit, params).where(actor:)
62
214
  end
63
215
 
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
216
+ # Returns a list of activities ordered by creation date.
217
+ def self.latest(limit = 20, params = { offset: 0 })
218
+ offset = params[:offset] || 0
219
+ LoggableActivity::Activity
220
+ .all
221
+ .order(created_at: :desc)
222
+ .includes(:payloads)
223
+ .offset(offset)
224
+ .limit(limit)
72
225
  end
73
226
 
227
+ private
228
+
74
229
  def update_attrs
75
230
  update_payload_attrs = attrs.find { |p| p[:payload_type] == 'update_payload' }
76
231
  return nil unless update_payload_attrs
@@ -79,42 +234,36 @@ module LoggableActivity
79
234
  update_payload_attrs
80
235
  end
81
236
 
82
- def previous_associations_attrs
83
- attrs.select { |p| p[:payload_type] == 'previous_association' }
237
+ def primary_payload
238
+ ordered_payloads.find { |p| p.payload_type == 'primary_payload' }
84
239
  end
85
240
 
86
- def record_display_name
87
- return I18n.t('loggable.activity.deleted') if encrypted_record_display_name.nil?
241
+ def updated_relations_attrs
242
+ grouped_associations = attrs.group_by { |p| p[:record_class] }
88
243
 
89
- LoggableActivity::Encryption.decrypt(encrypted_record_display_name, record_key)
90
- end
244
+ grouped_associations.map do |record_class, payloads|
245
+ previous_attrs = payloads.find { |p| p[:payload_type] == 'previous_association' }
246
+ current_attrs = payloads.find { |p| p[:payload_type] == 'current_association' }
247
+ next if previous_attrs.nil? && current_attrs.nil?
91
248
 
92
- def actor_display_name
93
- return I18n.t('loggable.activity.deleted') if encrypted_actor_display_name.nil?
249
+ { record_class:, previous_attrs:, current_attrs: }
250
+ end.compact
251
+ end
94
252
 
95
- LoggableActivity::Encryption.decrypt(encrypted_actor_display_name, actor_key)
253
+ def previous_associations_attrs
254
+ attrs.select { |p| p[:payload_type] == 'previous_association' }
96
255
  end
97
256
 
98
- def actor_key
99
- LoggableActivity::EncryptionKey.for_record(actor)&.key
257
+ def ordered_payloads
258
+ payloads.order(:payload_type)
100
259
  end
101
260
 
102
261
  def record_key
103
262
  LoggableActivity::EncryptionKey.for_record(record)&.key
104
263
  end
105
264
 
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)
265
+ def actor_key
266
+ LoggableActivity::EncryptionKey.for_record(actor)&.key
118
267
  end
119
268
 
120
269
  def must_have_at_least_one_payload
@@ -1,11 +1,29 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LoggableActivity
4
+ # This class is used to load the configuration file located at config/loggable_activity.yml
4
5
  class Configuration
5
6
  def self.load_config_file(config_file_path)
6
7
  @config_data = YAML.load_file(config_file_path)
7
8
  end
8
9
 
10
+ # Returns the configuration data for the given class
11
+ #
12
+ # Example:
13
+ # LoggableActivity::Configuration.for_class('User')
14
+ # Returns:
15
+ # {
16
+ # "record_display_name": "full_name",
17
+ # "loggable_attrs": [
18
+ # "first_name",
19
+ # "last_name",
20
+ # ],
21
+ # "auto_log": [
22
+ # "create",
23
+ # "update",
24
+ # "destroy"
25
+ # ]
26
+ # }
9
27
  def self.for_class(class_name)
10
28
  @config_data[class_name]
11
29
  end
@@ -5,10 +5,20 @@ require 'openssl'
5
5
  require 'base64'
6
6
 
7
7
  module LoggableActivity
8
+ # This error is raised when encryption or decryption fails
8
9
  class EncryptionError < StandardError
9
10
  end
10
11
 
12
+ # This module is used to encrypt and decrypt attributes
11
13
  module Encryption
14
+ # Encrypts the given data using the given encryption key
15
+ #
16
+ # Example:
17
+ # LoggableActivity::Encryption.encrypt('my secret data', 'my secret key')
18
+ #
19
+ # Returns:
20
+ # "SOME_ENCRYPTED_STRING"
21
+ #
12
22
  def self.encrypt(data, encryption_key)
13
23
  return nil if data.nil?
14
24
  return nil if encryption_key.nil?
@@ -22,8 +32,17 @@ module LoggableActivity
22
32
  raise EncryptionError, "Encryption failed: #{e.message} ***"
23
33
  end
24
34
 
35
+ # Decrypts the given data using the given encryption key
36
+ #
37
+ # Example:
38
+ # LoggableActivity::Encryption.decrypt('SOME_ENCRYPTED_STRING', 'SECRET_KEY')
39
+ #
40
+ # Returns:
41
+ # "my secret data"
42
+ #
25
43
  def self.decrypt(data, encryption_key)
26
- return I18n.t('loggable.activity.deleted') if blank?(data) || blank?(encryption_key)
44
+ return nil if data.nil?
45
+ return I18n.t('loggable.activity.deleted') if encryption_key.nil?
27
46
 
28
47
  cipher = OpenSSL::Cipher.new('AES-128-CBC').decrypt
29
48
  cipher.key = Digest::SHA1.hexdigest(encryption_key)[0..15]