audited-serialize 0.0.2 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aa2ae142361013574ee5100ed3edf7da72ffa6a04758a894dfab763a3c37b82e
4
- data.tar.gz: cee3114d051d34099d11d9f9f402c7dffa8a0d61c813d472a11f73a5afafabed
3
+ metadata.gz: c13c23cc79d29cf37a1c663634909b2f699bb38a7e69722d0d68c71159d01d96
4
+ data.tar.gz: a65ad64ea718d380b56711155a13dc2bb7f85fb65143ef52079ae584816960a8
5
5
  SHA512:
6
- metadata.gz: 929cd4a6b8a55c730db3d644755f23cc33bb27f5e39553bd54cf67b8d6bcea0fe80c6b84eb412d7f4c7e3c03851493022d40c3fb177e908c5fb5ea919d6f4d35
7
- data.tar.gz: f79cac8c70bddc12ee980194d557d9fb1f7e8d04c45d5083fdecd996015e3df1e9c31f7ed090866560263182251546675380a1050895ec9f8a4229668b2b4eca
6
+ metadata.gz: c24d1457e9cf4f2103d38ac8f37bde5799b13bc812cea1a3cded11f5743e8b728761ab267bc6578de42ea21c60e890305f35fe7bdf8dca11df9bc5e507fc0e5f
7
+ data.tar.gz: 9eacbfb7355928d94a0c948d7063fe5d50d2ccb8f695b173b5718a97a3648b85aa49b7f10d8c9ecfc8b6d082520c52ca09877c89684d0980ede7e02d6dc8f2ab
data/README.md CHANGED
@@ -26,6 +26,31 @@ audit = Audited::Audit.first
26
26
  audit.changes_list
27
27
  ```
28
28
 
29
+ ## Заголовки аудит-логов
30
+
31
+ На экземплярах audit-класса доступен метод `.title` для вывода заголовка c информацией о том, какое действие на какой сущности было совершено
32
+
33
+ ```
34
+ audit = Audited::Audit.first
35
+ audit.title
36
+
37
+ => "Изменение пользователя"
38
+ ```
39
+
40
+ ## Заголовки связанных записей
41
+
42
+ При наличии в аудит-логах полей, содержащих ID связанных сущностей, по умолчанию будет отображено название (поле `name`) этой сущности. При отсутствии у сущности поля `name` или необходимости отображения значения другого поля можно задать название этого поля в модели
43
+
44
+ ```
45
+ # app/models/user.rb
46
+
47
+ class User < ApplicationRecord
48
+
49
+ audit title: :email
50
+
51
+ end
52
+ ```
53
+
29
54
  ## Конфигурация
30
55
 
31
56
  Изменение настроек сериализации осуществляется путем редактирования стандартного файла конфигурации `Audited`
@@ -38,7 +63,7 @@ Audited.config do |config|
38
63
  end
39
64
  ```
40
65
 
41
- ### Исключения
66
+ ## Исключения
42
67
 
43
68
  Для добавления исключений для полей сущностей, которые не будут отображаться в списке добавьте в конфиг `serialization_exceptions`.
44
69
 
@@ -0,0 +1,41 @@
1
+ require 'audited/serialization'
2
+ require 'audited/serialization_changes/array_module'
3
+ require 'audited/serialization_changes/boolean_module'
4
+ require 'audited/serialization_changes/common_module'
5
+ require 'audited/serialization_changes/date_module'
6
+ require 'audited/serialization_changes/datetime_module'
7
+ require 'audited/serialization_changes/enum_module'
8
+ require 'audited/serialization_changes/object_module'
9
+ require 'audited/serialization_changes/related_record_module'
10
+
11
+ module Audited
12
+ class Audit < ::ActiveRecord::Base
13
+
14
+ include Audited::Serialization
15
+ include Audited::SerializationChanges::ArrayModule
16
+ include Audited::SerializationChanges::BooleanModule
17
+ include Audited::SerializationChanges::CommonModule
18
+ include Audited::SerializationChanges::DateModule
19
+ include Audited::SerializationChanges::DatetimeModule
20
+ include Audited::SerializationChanges::EnumModule
21
+ include Audited::SerializationChanges::ObjectModule
22
+ include Audited::SerializationChanges::RelatedRecordModule
23
+
24
+ scope :own_and_associated_for, (lambda do |record|
25
+ where('
26
+ (auditable_type = :type AND auditable_id = :id)
27
+ OR
28
+ (associated_type = :type AND associated_id = :id)',
29
+ type: record.class.to_s, id: record.id
30
+ ).order(id: :desc)
31
+ end)
32
+
33
+ def title
34
+ operation = I18n.t("audited.actions.#{action}")
35
+ entity = I18n.t("audited.auditable_types.#{auditable_type}")
36
+
37
+ "#{operation} #{entity}"
38
+ end
39
+
40
+ end
41
+ end
@@ -4,21 +4,29 @@ module Audited
4
4
  extend ActiveSupport::Concern
5
5
 
6
6
  def changes_list
7
- model = auditable_type.constantize
7
+ # проверка на наличие модели
8
+ # в случае ее отсутствия, верятнее всего она была удалена
9
+ begin
10
+ model = auditable_type.constantize
11
+ rescue NameError
12
+ return
13
+ end
14
+
8
15
  columns_hash = model.columns_hash
9
- @reflections = model.reflections.to_h { |_relation, reflection| [reflection.foreign_key, reflection.klass] }
16
+ @reflections = model_reflections(model)
10
17
 
11
18
  audited_changes.map do |column, value|
12
- @column = column
13
-
14
19
  # пропускаем, если колонка в списке исключений
15
- next if Audited.serialization_exceptions[auditable_type]&.include?(@column)
20
+ next if Audited.serialization_exceptions[auditable_type]&.include?(column)
16
21
 
17
- # поле таблицы БД
22
+ @column = column
18
23
  @db_column = columns_hash[column]
19
24
 
25
+ # пропускаем, если колонка теперь отсутствует в БД
26
+ next unless @db_column
27
+
20
28
  # русскоязычное название поля
21
- @field = @db_column.comment
29
+ field = password_changes? ? 'Пароль' : @db_column.comment
22
30
 
23
31
  if action == 'update' && value.is_a?(Array)
24
32
  # значения, измененные во время редактирования
@@ -28,158 +36,45 @@ module Audited
28
36
  @changed = value
29
37
  end
30
38
 
31
- if related_record_changed?
32
- related_record_changes
33
- elsif object?
34
- json_changes
35
- elsif array?
36
- array_changes
37
- elsif password?
38
- password_changes
39
- elsif date?
40
- date_changes
41
- elsif datetime?
42
- datetime_changes
43
- elsif boolean?
44
- boolean_changes
45
- elsif enum_changes?
46
- enum_changes
47
- else
48
- common_column_changes
49
- end
39
+ # определение изменений было/стало
40
+ from, to = changes_from_to
50
41
 
51
- next if @from.blank? && @to.blank?
42
+ # пропускаем, если изменения не зафиксированы
43
+ next if from.blank? && to.blank?
52
44
 
53
45
  {
54
- field: @field,
55
- from: @from,
56
- to: @to
46
+ field:, from:, to:
57
47
  }
58
48
  end.compact
59
49
  end
60
50
 
61
51
  private
62
52
 
63
- def related_record_changed?
64
- @reflections[@column].present?
65
- end
66
-
67
- def object?
68
- @initial.is_a?(Hash) || @changed.is_a?(Hash)
69
- end
70
-
71
- def array?
72
- @initial.is_a?(Array) || @changed.is_a?(Array)
73
- end
74
-
75
- def password?
76
- @column == 'encrypted_password'
77
- end
78
-
79
- def datetime?
80
- @initial&.to_date&.acts_like?(:date) && @initial.include?(':') rescue false
81
- @changed&.to_date&.acts_like?(:date) && @changed.include?(':') rescue false
82
- end
83
-
84
- def date?
85
- @initial&.to_date&.acts_like?(:date) && @initial.to_s.include?('-') && @initial.to_s.exclude?(':') rescue false
86
- @changed&.to_date&.acts_like?(:date) && @changed.to_s.include?('-') && @changed.to_s.exclude?(':') rescue false
87
- end
88
-
89
- def boolean?
90
- bool_classes = [TrueClass, FalseClass]
91
-
92
- bool_classes.include?(@initial.class) || bool_classes.include?(@changed.class)
93
- end
94
-
95
- def enum_changes?
96
- @db_column.type == :enum
97
- end
98
-
99
- def related_record_changes
100
- # модель связанной сущности от колонки
101
- related_model = @reflections[@column]
102
-
103
- # заданные/измененные значения
104
- @from = related_record_value(related_model, @initial)
105
- @to = related_record_value(related_model, @changed)
106
- end
107
-
108
- def related_record_value(related_model, value)
109
- if value
110
- record = related_model.find_by(id: value)
111
- auditing_title(record) || "Запись ##{value}"
53
+ def model_reflections(model)
54
+ model.reflections.to_h { |_rel, reflection| [reflection.foreign_key, reflection.klass] }
55
+ end
56
+
57
+ def changes_from_to
58
+ if related_record_changes?
59
+ related_record_changes
60
+ elsif object_changes?
61
+ object_changes
62
+ elsif array_changes?
63
+ array_changes
64
+ elsif password_changes?
65
+ password_changes
66
+ elsif date_changes?
67
+ date_changes
68
+ elsif datetime_changes?
69
+ datetime_changes
70
+ elsif boolean_changes?
71
+ boolean_changes
72
+ elsif enum_changes?
73
+ enum_changes
112
74
  else
113
- ''
75
+ common_column_changes
114
76
  end
115
77
  end
116
78
 
117
- def auditing_title(record)
118
- return unless record
119
-
120
- if record.is_a?(House)
121
- record.number
122
- elsif record.klass.column_names.include?('name')
123
- record.name
124
- else
125
- "##{record.id}"
126
- end
127
- end
128
-
129
- def enum_changes
130
- enum_type = @db_column.sql_type
131
- values = I18n.t("enums.#{enum_type}").stringify_keys
132
-
133
- @from = values[@initial]
134
- @to = values[@changed]
135
- end
136
-
137
- def json_changes
138
- # удаление дубликатов ключей/значений
139
- initial = (@initial.to_a - @changed.to_a).to_h
140
- changed = (@changed.to_a - @initial.to_a).to_h
141
-
142
- @from = initial.map { |k, v| "#{k.humanize}: #{v}" }
143
- @to = changed.map { |k, v| "#{k.humanize}: #{v}" }
144
- end
145
-
146
- def array_changes
147
- @from = @initial&.join(', ')
148
- @to = @changed&.join(', ')
149
- end
150
-
151
- def password_changes
152
- @field = 'Пароль'
153
- @from = nil
154
- @to = '<новый>'
155
- end
156
-
157
- def date_changes
158
- @from = Date.parse(@initial).strftime('%d.%m.%Y') if @initial.present?
159
- @to = Date.parse(@changed).strftime('%d.%m.%Y') if @changed.present?
160
- end
161
-
162
- def datetime_changes
163
- if @initial.present?
164
- @from = DateTime.parse(@initial).in_time_zone('Europe/Moscow').strftime('%d.%m.%Y %H:%M')
165
- end
166
-
167
- if @changed.present?
168
- @to = DateTime.parse(@changed).in_time_zone('Europe/Moscow').strftime('%d.%m.%Y %H:%M')
169
- end
170
- end
171
-
172
- def boolean_changes
173
- values = { true => 'Да', false => 'Нет' }
174
-
175
- @from = values[@initial]
176
- @to = values[@changed]
177
- end
178
-
179
- def common_column_changes
180
- @from = @initial
181
- @to = @changed
182
- end
183
-
184
79
  end
185
80
  end
@@ -0,0 +1,22 @@
1
+ module Audited
2
+ module SerializationChanges
3
+ module ArrayModule
4
+
5
+ extend ActiveSupport::Concern
6
+
7
+ private
8
+
9
+ def array_changes?
10
+ @initial.is_a?(Array) || @changed.is_a?(Array)
11
+ end
12
+
13
+ def array_changes
14
+ from = @initial&.join(', ')
15
+ to = @changed&.join(', ')
16
+
17
+ return from, to
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,23 @@
1
+ module Audited
2
+ module SerializationChanges
3
+ module BooleanModule
4
+
5
+ extend ActiveSupport::Concern
6
+
7
+ private
8
+
9
+ def boolean_changes?
10
+ classes = [TrueClass, FalseClass]
11
+
12
+ classes.include?(@initial.class) || classes.include?(@changed.class)
13
+ end
14
+
15
+ def boolean_changes
16
+ values = { true => 'Да', false => 'Нет' }
17
+
18
+ return values[@initial], values[@changed]
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ module Audited
2
+ module SerializationChanges
3
+ module CommonModule
4
+
5
+ extend ActiveSupport::Concern
6
+
7
+ private
8
+
9
+ def password_changes?
10
+ @column == 'encrypted_password'
11
+ end
12
+
13
+ def password_changes
14
+ return nil, '<новый>'
15
+ end
16
+
17
+ def common_column_changes
18
+ return @initial, @changed
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,29 @@
1
+ module Audited
2
+ module SerializationChanges
3
+ module DateModule
4
+
5
+ extend ActiveSupport::Concern
6
+
7
+ private
8
+
9
+ def date_changes?
10
+ @initial&.to_date&.acts_like?(:date) && @initial.to_s.include?('-') && @initial.to_s.exclude?(':') rescue false
11
+ @changed&.to_date&.acts_like?(:date) && @changed.to_s.include?('-') && @changed.to_s.exclude?(':') rescue false
12
+ end
13
+
14
+ def date_changes
15
+ from = date_change_formatted(@initial)
16
+ to = date_change_formatted(@changed)
17
+
18
+ return from, to
19
+ end
20
+
21
+ def date_change_formatted(value)
22
+ return if value.blank?
23
+
24
+ Date.parse(value).strftime('%d.%m.%Y')
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,29 @@
1
+ module Audited
2
+ module SerializationChanges
3
+ module DatetimeModule
4
+
5
+ extend ActiveSupport::Concern
6
+
7
+ private
8
+
9
+ def datetime_changes?
10
+ @initial&.to_date&.acts_like?(:date) && @initial.include?(':') rescue false
11
+ @changed&.to_date&.acts_like?(:date) && @changed.include?(':') rescue false
12
+ end
13
+
14
+ def datetime_changes
15
+ from = datetime_change_formatted(@initial)
16
+ to = datetime_change_formatted(@changed)
17
+
18
+ return from, to
19
+ end
20
+
21
+ def datetime_change_formatted(value)
22
+ return if value.blank?
23
+
24
+ DateTime.parse(value).in_time_zone('Europe/Moscow').strftime('%d.%m.%Y %H:%M')
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,22 @@
1
+ module Audited
2
+ module SerializationChanges
3
+ module EnumModule
4
+
5
+ extend ActiveSupport::Concern
6
+
7
+ private
8
+
9
+ def enum_changes?
10
+ @db_column.type == :enum
11
+ end
12
+
13
+ def enum_changes
14
+ type = @db_column.sql_type
15
+ values = I18n.t("enums.#{type}").stringify_keys
16
+
17
+ return values[@initial], values[@changed]
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,29 @@
1
+ module Audited
2
+ module SerializationChanges
3
+ module ObjectModule
4
+
5
+ extend ActiveSupport::Concern
6
+
7
+ private
8
+
9
+ def object_changes?
10
+ @initial.is_a?(Hash) || @changed.is_a?(Hash)
11
+ end
12
+
13
+ def object_changes
14
+ from = object_change_formatted(@initial, @changed)
15
+ to = object_change_formatted(@changed, @initial)
16
+
17
+ return from, to
18
+ end
19
+
20
+ def object_change_formatted(from, to)
21
+ # удаление дубликатов ключей/значений
22
+ hash = (from.to_a - to.to_a).to_h
23
+
24
+ hash.map { |key, val| "#{key.humanize}: #{val}" }
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,47 @@
1
+ module Audited
2
+ module SerializationChanges
3
+ module RelatedRecordModule
4
+
5
+ extend ActiveSupport::Concern
6
+
7
+ private
8
+
9
+ def related_record_changes?
10
+ @reflections[@column].present?
11
+ end
12
+
13
+ def related_record_changes
14
+ # модель связанной сущности от колонки
15
+ related_model = @reflections[@column]
16
+
17
+ # заданные/измененные значения
18
+ from = related_record_value(related_model, @initial)
19
+ to = related_record_value(related_model, @changed)
20
+
21
+ return from, to
22
+ end
23
+
24
+ def related_record_value(related_model, related_record_id)
25
+ return '' unless related_record_id
26
+
27
+ record = related_model.find_by(id: related_record_id)
28
+ return "Запись ##{related_record_id}" unless record
29
+
30
+ related_record_auditing_title(record)
31
+ end
32
+
33
+ def related_record_auditing_title(record)
34
+ audited_title = record.class.audited_options[:title]
35
+
36
+ if audited_title
37
+ record.send(audited_title)
38
+ elsif record.class.column_names.include?('name')
39
+ record.name
40
+ else
41
+ "##{record.id}"
42
+ end
43
+ end
44
+
45
+ end
46
+ end
47
+ end
@@ -1,5 +1,5 @@
1
1
  require 'audited_config'
2
- require 'audited/original_audit'
2
+ require 'audited/audit_extensions'
3
3
 
4
4
  module AuditedSerialize
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: audited-serialize
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Павел Бабин
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-03-12 00:00:00.000000000 Z
11
+ date: 2024-03-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: audited
@@ -32,8 +32,16 @@ extra_rdoc_files: []
32
32
  files:
33
33
  - README.md
34
34
  - lib/audited-serialize.rb
35
- - lib/audited/original_audit.rb
35
+ - lib/audited/audit_extensions.rb
36
36
  - lib/audited/serialization.rb
37
+ - lib/audited/serialization_changes/array_module.rb
38
+ - lib/audited/serialization_changes/boolean_module.rb
39
+ - lib/audited/serialization_changes/common_module.rb
40
+ - lib/audited/serialization_changes/date_module.rb
41
+ - lib/audited/serialization_changes/datetime_module.rb
42
+ - lib/audited/serialization_changes/enum_module.rb
43
+ - lib/audited/serialization_changes/object_module.rb
44
+ - lib/audited/serialization_changes/related_record_module.rb
37
45
  - lib/audited_config.rb
38
46
  - lib/audited_serialize.rb
39
47
  homepage:
@@ -1,9 +0,0 @@
1
- require 'audited/serialization'
2
-
3
- module Audited
4
- class Audit < ::ActiveRecord::Base
5
-
6
- include Audited::Serialization
7
-
8
- end
9
- end