paper_trail_manager 0.7.0 → 0.9.0
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.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +13 -47
- data/.gitignore +2 -2
- data/.ruby-version +1 -0
- data/Appraisals +9 -17
- data/CHANGES.md +29 -0
- data/README.md +130 -66
- data/Rakefile +5 -3
- data/app/controllers/paper_trail_manager/changes_controller.rb +24 -9
- data/app/helpers/paper_trail_manager/changes_helper.rb +2 -2
- data/app/views/paper_trail_manager/changes/_version.html.erb +5 -5
- data/app/views/paper_trail_manager/changes/index.html.erb +44 -30
- data/app/views/paper_trail_manager/changes/show.html.erb +10 -7
- data/config/locales/en.yml +30 -0
- data/gemfiles/rails_6.1_paper_trail_12.0_kaminari.gemfile +10 -0
- data/gemfiles/rails_6.1_paper_trail_12.0_will_paginate.gemfile +10 -0
- data/gemfiles/rails_7.0_paper_trail_12.0_kaminari.gemfile +10 -0
- data/gemfiles/rails_7.0_paper_trail_12.0_will_paginate.gemfile +10 -0
- data/gemfiles/rails_7.0_paper_trail_15.0_kaminari.gemfile +10 -0
- data/gemfiles/rails_7.0_paper_trail_15.0_will_paginate.gemfile +10 -0
- data/gemfiles/rails_7.1_paper_trail_15.0_kaminari.gemfile +10 -0
- data/gemfiles/rails_7.1_paper_trail_15.0_will_paginate.gemfile +10 -0
- data/lib/generators/paper_trail_manager/install/install_generator.rb +36 -0
- data/lib/generators/paper_trail_manager/install/templates/initializer.rb +35 -0
- data/lib/paper_trail_manager.rb +8 -2
- data/paper_trail_manager.gemspec +14 -14
- data/spec/app_template.rb +19 -10
- data/spec/integration/authorization_spec.rb +84 -0
- data/spec/integration/date_filter_spec.rb +84 -0
- data/spec/integration/navigation_spec.rb +1 -1
- data/spec/integration/paper_trail_manager_spec.rb +6 -6
- data/spec/integration/response_formats_spec.rb +73 -0
- data/spec/support/factories.rb +2 -2
- data/spec/unit/authorization_spec.rb +42 -0
- data/spec/unit/changes_helper_spec.rb +81 -0
- metadata +78 -59
- data/gemfiles/rails_4.2.2_paper_trail_3.0_kaminari.gemfile +0 -13
- data/gemfiles/rails_4.2.2_paper_trail_3.0_will_paginate.gemfile +0 -13
- data/gemfiles/rails_4.2.2_paper_trail_4.0_kaminari.gemfile +0 -13
- data/gemfiles/rails_4.2.2_paper_trail_4.0_will_paginate.gemfile +0 -13
- data/gemfiles/rails_4.2.2_paper_trail_5.0_kaminari.gemfile +0 -13
- data/gemfiles/rails_4.2.2_paper_trail_5.0_will_paginate.gemfile +0 -13
- data/gemfiles/rails_4.2.2_paper_trail_6.0_kaminari.gemfile +0 -13
- data/gemfiles/rails_4.2.2_paper_trail_6.0_will_paginate.gemfile +0 -13
- data/gemfiles/rails_4.2.2_paper_trail_7.0_kaminari.gemfile +0 -13
- data/gemfiles/rails_4.2.2_paper_trail_7.0_will_paginate.gemfile +0 -13
- data/gemfiles/rails_4.2.2_paper_trail_8.0_kaminari.gemfile +0 -13
- data/gemfiles/rails_4.2.2_paper_trail_8.0_will_paginate.gemfile +0 -13
- data/gemfiles/rails_5.0.0_paper_trail_5.0_kaminari.gemfile +0 -13
- data/gemfiles/rails_5.0.0_paper_trail_5.0_will_paginate.gemfile +0 -13
- data/gemfiles/rails_5.0.0_paper_trail_6.0_kaminari.gemfile +0 -13
- data/gemfiles/rails_5.0.0_paper_trail_6.0_will_paginate.gemfile +0 -13
- data/gemfiles/rails_5.0.0_paper_trail_7.0_kaminari.gemfile +0 -13
- data/gemfiles/rails_5.0.0_paper_trail_7.0_will_paginate.gemfile +0 -13
- data/gemfiles/rails_5.0.0_paper_trail_8.0_kaminari.gemfile +0 -13
- data/gemfiles/rails_5.0.0_paper_trail_8.0_will_paginate.gemfile +0 -13
- data/gemfiles/rails_5.1.0_paper_trail_10.0_kaminari.gemfile +0 -13
- data/gemfiles/rails_5.1.0_paper_trail_10.0_will_paginate.gemfile +0 -13
- data/gemfiles/rails_5.1.0_paper_trail_7.0_kaminari.gemfile +0 -13
- data/gemfiles/rails_5.1.0_paper_trail_7.0_will_paginate.gemfile +0 -13
- data/gemfiles/rails_5.1.0_paper_trail_8.0_kaminari.gemfile +0 -13
- data/gemfiles/rails_5.1.0_paper_trail_8.0_will_paginate.gemfile +0 -13
- data/gemfiles/rails_5.1.0_paper_trail_9.0_kaminari.gemfile +0 -13
- data/gemfiles/rails_5.1.0_paper_trail_9.0_will_paginate.gemfile +0 -13
- data/gemfiles/rails_5.2.0_paper_trail_10.0_kaminari.gemfile +0 -13
- data/gemfiles/rails_5.2.0_paper_trail_10.0_will_paginate.gemfile +0 -13
- data/gemfiles/rails_5.2.0_paper_trail_9.0_kaminari.gemfile +0 -13
- data/gemfiles/rails_5.2.0_paper_trail_9.0_will_paginate.gemfile +0 -13
- data/gemfiles/rails_6.0.0_paper_trail_10.0_kaminari.gemfile +0 -14
- data/gemfiles/rails_6.0.0_paper_trail_10.0_will_paginate.gemfile +0 -15
|
@@ -1,35 +1,49 @@
|
|
|
1
|
-
<h1
|
|
2
|
-
|
|
3
|
-
<p class='changes_feed'><%= link_to 'Changes feed', changes_path(:format => 'atom') %></p>
|
|
1
|
+
<h1><%= t('paper_trail_manager.changes.index.title') %></h1>
|
|
4
2
|
|
|
5
3
|
<p>
|
|
6
|
-
|
|
7
|
-
<%= ([link_to('
|
|
4
|
+
<%= t('paper_trail_manager.changes.index.show_label') %>
|
|
5
|
+
<%= ([link_to(t('paper_trail_manager.changes.index.all'), changes_path)] + change_item_types.map { |type| link_to(type.pluralize, changes_path(type: type)) }).join(' | ').html_safe %>
|
|
8
6
|
</p>
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
</tr>
|
|
23
|
-
</thead>
|
|
24
|
-
<tbody>
|
|
25
|
-
<% if @versions.any? %>
|
|
26
|
-
<% @versions.each do |version| %>
|
|
27
|
-
<% next unless change_show_allowed?(version) %>
|
|
28
|
-
<%= render :partial => 'version', :object => version %>
|
|
29
|
-
<% end %>
|
|
30
|
-
<% else %>
|
|
31
|
-
<td rowspan='2'> — No changes found — </td>
|
|
32
|
-
<% end %>
|
|
33
|
-
</tbody>
|
|
34
|
-
</table>
|
|
8
|
+
<%= form_tag changes_path, method: :get, class: 'changes_date_filter' do %>
|
|
9
|
+
<%= hidden_field_tag :type, params[:type] if params[:type] %>
|
|
10
|
+
<%= hidden_field_tag :id, params[:id] if params[:id] %>
|
|
11
|
+
<label for="from"><%= t('paper_trail_manager.changes.filter.from') %></label>
|
|
12
|
+
<%= date_field_tag :from, params[:from], id: 'from' %>
|
|
13
|
+
<label for="to"><%= t('paper_trail_manager.changes.filter.to') %></label>
|
|
14
|
+
<%= date_field_tag :to, params[:to], id: 'to' %>
|
|
15
|
+
<%= submit_tag t('paper_trail_manager.changes.filter.submit'), name: nil %>
|
|
16
|
+
<% if params[:from].present? || params[:to].present? %>
|
|
17
|
+
<%= link_to t('paper_trail_manager.changes.filter.clear'), changes_path(type: params[:type], id: params[:id]), class: 'clear_filter' %>
|
|
18
|
+
<% end %>
|
|
19
|
+
<% end %>
|
|
35
20
|
|
|
21
|
+
<div class="table-responsive">
|
|
22
|
+
<table class='changes_table table table-bordered'>
|
|
23
|
+
<tfoot>
|
|
24
|
+
<tr>
|
|
25
|
+
<td colspan='2'>
|
|
26
|
+
<%= paginate @versions %>
|
|
27
|
+
</td>
|
|
28
|
+
</tr>
|
|
29
|
+
</tfoot>
|
|
30
|
+
<thead>
|
|
31
|
+
<tr class='changes_header'>
|
|
32
|
+
<th class='change_time'><%= t('paper_trail_manager.changes.index.time') %></th>
|
|
33
|
+
<th class='change_details'><%= t('paper_trail_manager.changes.index.details') %></th>
|
|
34
|
+
</tr>
|
|
35
|
+
</thead>
|
|
36
|
+
<tbody>
|
|
37
|
+
<% if @versions.any? %>
|
|
38
|
+
<% @versions.each do |version| %>
|
|
39
|
+
<% next unless change_show_allowed?(version) %>
|
|
40
|
+
<%= render partial: 'version', object: version %>
|
|
41
|
+
<% end %>
|
|
42
|
+
<% else %>
|
|
43
|
+
<tr>
|
|
44
|
+
<td colspan='2'> — <%= t('paper_trail_manager.changes.index.no_changes') %> — </td>
|
|
45
|
+
</tr>
|
|
46
|
+
<% end %>
|
|
47
|
+
</tbody>
|
|
48
|
+
</table>
|
|
49
|
+
</div>
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
<h1
|
|
1
|
+
<h1><%= t('paper_trail_manager.changes.show.title', id: @version.id) %></h1>
|
|
2
2
|
|
|
3
3
|
<table class='changes_table'>
|
|
4
|
-
<
|
|
5
|
-
<
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
<thead>
|
|
5
|
+
<tr class='changes_header'>
|
|
6
|
+
<th class='change_time'><%= t('paper_trail_manager.changes.index.time') %></th>
|
|
7
|
+
<th class='change_details'><%= t('paper_trail_manager.changes.index.details') %></th>
|
|
8
|
+
</tr>
|
|
9
|
+
</thead>
|
|
10
|
+
<tbody>
|
|
11
|
+
<%= render partial: 'version', object: @version %>
|
|
12
|
+
</tbody>
|
|
9
13
|
</table>
|
|
10
|
-
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
en:
|
|
2
|
+
paper_trail_manager:
|
|
3
|
+
changes:
|
|
4
|
+
index:
|
|
5
|
+
title: "Changes"
|
|
6
|
+
show_label: "Show:"
|
|
7
|
+
all: "All"
|
|
8
|
+
no_changes: "No changes found"
|
|
9
|
+
time: "Time"
|
|
10
|
+
details: "Attribute with previous and current values"
|
|
11
|
+
show:
|
|
12
|
+
title: "Change %{id}"
|
|
13
|
+
filter:
|
|
14
|
+
from: "From:"
|
|
15
|
+
to: "To:"
|
|
16
|
+
submit: "Filter"
|
|
17
|
+
clear: "Clear"
|
|
18
|
+
version:
|
|
19
|
+
change_id: "Change #%{id}"
|
|
20
|
+
roll_back: "Roll back"
|
|
21
|
+
confirm_rollback: "Are you sure?"
|
|
22
|
+
by: "by"
|
|
23
|
+
flash:
|
|
24
|
+
index_denied: "You do not have permission to list changes."
|
|
25
|
+
show_denied: "You do not have permission to show that change."
|
|
26
|
+
revert_denied: "You do not have permission to revert this change."
|
|
27
|
+
not_found: "No such version."
|
|
28
|
+
rollback_create: "Rolled back newly-created record by destroying it."
|
|
29
|
+
rollback_update: "Rolled back changes to this record."
|
|
30
|
+
rollback_failed: "Couldn't rollback. Sorry."
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rails/generators'
|
|
4
|
+
|
|
5
|
+
class PaperTrailManager
|
|
6
|
+
class InstallGenerator < Rails::Generators::Base
|
|
7
|
+
source_root File.expand_path('templates', __dir__)
|
|
8
|
+
desc 'Install PaperTrailManager: add route and create initializer'
|
|
9
|
+
|
|
10
|
+
def add_route
|
|
11
|
+
route_string = "resources :changes, controller: 'paper_trail_manager/changes'"
|
|
12
|
+
routes_file = File.join(destination_root, 'config/routes.rb')
|
|
13
|
+
|
|
14
|
+
if File.exist?(routes_file) && File.read(routes_file).include?(route_string)
|
|
15
|
+
say_status :skip, 'Route already exists', :yellow
|
|
16
|
+
else
|
|
17
|
+
route route_string
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def create_initializer
|
|
22
|
+
template 'initializer.rb', 'config/initializers/paper_trail_manager.rb'
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def show_post_install
|
|
26
|
+
say ''
|
|
27
|
+
say '✅ PaperTrailManager installed!', :green
|
|
28
|
+
say ''
|
|
29
|
+
say 'Next steps:'
|
|
30
|
+
say ' 1. Restart your Rails server'
|
|
31
|
+
say ' 2. Visit /changes to browse your PaperTrail version history'
|
|
32
|
+
say ' 3. Edit config/initializers/paper_trail_manager.rb to customize authorization'
|
|
33
|
+
say ''
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# PaperTrailManager configuration
|
|
4
|
+
# See: https://github.com/DamageLabs/paper_trail_manager
|
|
5
|
+
|
|
6
|
+
# Control who can view the changes index.
|
|
7
|
+
# PaperTrailManager.allow_index_when do |controller|
|
|
8
|
+
# controller.current_user.present?
|
|
9
|
+
# end
|
|
10
|
+
|
|
11
|
+
# Control who can view individual change details.
|
|
12
|
+
# Defaults to the allow_index rules if not set separately.
|
|
13
|
+
# PaperTrailManager.allow_show_when do |controller, version|
|
|
14
|
+
# controller.current_user.present?
|
|
15
|
+
# end
|
|
16
|
+
|
|
17
|
+
# Control who can revert changes.
|
|
18
|
+
# PaperTrailManager.allow_revert_when do |controller, version|
|
|
19
|
+
# controller.current_user&.admin?
|
|
20
|
+
# end
|
|
21
|
+
|
|
22
|
+
# Configure how to look up users referenced in PaperTrail's whodunnit column.
|
|
23
|
+
# PaperTrailManager.whodunnit_class = User
|
|
24
|
+
# PaperTrailManager.whodunnit_name_method = :name
|
|
25
|
+
|
|
26
|
+
# Specify a method to identify items on the index page.
|
|
27
|
+
# PaperTrailManager.item_name_method = :name
|
|
28
|
+
|
|
29
|
+
# Customize the user path helper (set to nil to disable user links).
|
|
30
|
+
# PaperTrailManager.user_path_method = :user_path
|
|
31
|
+
|
|
32
|
+
# When embedding inside another Rails engine:
|
|
33
|
+
# PaperTrailManager.base_controller = 'MyEngine::ApplicationController'
|
|
34
|
+
# PaperTrailManager.route_helpers = MyEngine::Engine.routes.url_helpers
|
|
35
|
+
# PaperTrailManager.layout = 'my_engine/application'
|
data/lib/paper_trail_manager.rb
CHANGED
|
@@ -14,8 +14,14 @@ rescue LoadError
|
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
class PaperTrailManager < Rails::Engine
|
|
17
|
+
initializer 'paper_trail_manager.i18n' do
|
|
18
|
+
config.i18n.load_path += Dir[root.join('config', 'locales', '*.yml')]
|
|
19
|
+
end
|
|
20
|
+
|
|
17
21
|
initializer 'paper_trail_manager.pagination' do
|
|
18
|
-
|
|
22
|
+
if defined?(WillPaginate)
|
|
23
|
+
::ActionView::Base.define_method(:paginate) { |*args, **kwargs, &block| will_paginate(*args, **kwargs, &block) }
|
|
24
|
+
end
|
|
19
25
|
end
|
|
20
26
|
|
|
21
27
|
@@whodunnit_name_method = :name
|
|
@@ -50,7 +56,7 @@ class PaperTrailManager < Rails::Engine
|
|
|
50
56
|
end
|
|
51
57
|
|
|
52
58
|
def self.allow_show?(controller, version)
|
|
53
|
-
|
|
59
|
+
allow_show_block.call controller, version
|
|
54
60
|
end
|
|
55
61
|
|
|
56
62
|
# Describe when to allow reverts. Call this with a block that accepts
|
data/paper_trail_manager.gemspec
CHANGED
|
@@ -5,28 +5,28 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
|
5
5
|
|
|
6
6
|
Gem::Specification.new do |spec|
|
|
7
7
|
spec.name = 'paper_trail_manager'
|
|
8
|
-
spec.version = '0.
|
|
8
|
+
spec.version = '0.9.0'
|
|
9
9
|
spec.authors = ['Igal Koshevoy', 'Reid Beels']
|
|
10
|
-
spec.
|
|
10
|
+
spec.email = ['mail@reidbeels.com']
|
|
11
11
|
spec.summary = 'A user interface for `paper_trail` versioning data in Rails applications.'
|
|
12
12
|
spec.description = 'Browse, subscribe, view and revert changes to records when using Rails and the `paper_trail` gem.'
|
|
13
|
-
spec.homepage = 'https://github.com/
|
|
13
|
+
spec.homepage = 'https://github.com/DamageLabs/paper_trail_manager'
|
|
14
14
|
spec.license = 'MIT'
|
|
15
|
-
|
|
16
15
|
spec.files = `git ls-files -z`.split("\x0")
|
|
17
16
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
18
17
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
19
18
|
spec.require_paths = ['lib']
|
|
20
|
-
|
|
21
|
-
spec.add_dependency 'paper_trail', ['>=
|
|
22
|
-
spec.add_dependency 'rails', ['>=
|
|
23
|
-
|
|
24
|
-
spec.
|
|
25
|
-
spec.add_development_dependency '
|
|
26
|
-
spec.add_development_dependency '
|
|
19
|
+
spec.required_ruby_version = '>= 3.1'
|
|
20
|
+
spec.add_dependency 'paper_trail', ['>= 12.0']
|
|
21
|
+
spec.add_dependency 'rails', ['>= 6.1', '< 8.0']
|
|
22
|
+
spec.add_dependency 'nokogiri', ['>= 1.18.3']
|
|
23
|
+
spec.add_dependency 'rails-html-sanitizer', ['>= 1.6.1']
|
|
24
|
+
spec.add_development_dependency 'appraisal', '~> 2.0'
|
|
25
|
+
spec.add_development_dependency 'factory_bot_rails', '~> 6.0'
|
|
26
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
|
27
27
|
spec.add_development_dependency 'rspec-activemodel-mocks', '~> 1.0'
|
|
28
|
-
spec.add_development_dependency 'rspec-html-matchers', '~> 0.
|
|
28
|
+
spec.add_development_dependency 'rspec-html-matchers', '~> 0.10'
|
|
29
29
|
spec.add_development_dependency 'rspec-its', '~> 1.0'
|
|
30
|
-
spec.add_development_dependency 'rspec-rails', '~>
|
|
31
|
-
spec.add_development_dependency 'sqlite3', '
|
|
30
|
+
spec.add_development_dependency 'rspec-rails', '~> 6.0'
|
|
31
|
+
spec.add_development_dependency 'sqlite3', '~> 1.7'
|
|
32
32
|
end
|
data/spec/app_template.rb
CHANGED
|
@@ -2,29 +2,38 @@
|
|
|
2
2
|
|
|
3
3
|
gem 'paper_trail_manager', path: __FILE__ + '/../../../'
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
append_to_file 'app/assets/config/manifest.js', "//= link application.js\n"
|
|
9
|
-
end
|
|
5
|
+
# Remove auto-generated request specs from dummy app
|
|
6
|
+
remove_file 'spec/requests/entities_spec.rb' if File.exist?('spec/requests/entities_spec.rb')
|
|
7
|
+
remove_file 'spec/requests/platforms_spec.rb' if File.exist?('spec/requests/platforms_spec.rb')
|
|
10
8
|
|
|
11
9
|
generate 'paper_trail:install'
|
|
12
10
|
generate 'resource', 'entity name:string status:string --no-controller-specs --no-helper-specs'
|
|
13
11
|
generate 'resource', 'platform name:string status:string --no-controller-specs --no-helper-specs'
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
remove_file 'spec/models/
|
|
13
|
+
# Remove auto-generated spec files that conflict with our factories
|
|
14
|
+
remove_file 'spec/models/entity_spec.rb' if File.exist?('spec/models/entity_spec.rb')
|
|
15
|
+
remove_file 'spec/models/platform_spec.rb' if File.exist?('spec/models/platform_spec.rb')
|
|
17
16
|
|
|
18
17
|
model_body = <<-MODEL
|
|
19
18
|
has_paper_trail
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
validates :name, presence: true
|
|
21
|
+
validates :status, presence: true
|
|
23
22
|
MODEL
|
|
24
23
|
|
|
25
24
|
inject_into_class 'app/models/entity.rb', 'Entity', model_body
|
|
26
25
|
inject_into_class 'app/models/platform.rb', 'Platform', model_body
|
|
27
26
|
|
|
28
|
-
route "resources :changes, :
|
|
27
|
+
route "resources :changes, controller: 'paper_trail_manager/changes'"
|
|
28
|
+
route "root to: 'paper_trail_manager/changes#index'"
|
|
29
|
+
|
|
30
|
+
# Allow YAML deserialization of ActiveSupport::TimeWithZone (Ruby 3.1+ Psych 4)
|
|
31
|
+
initializer 'permitted_classes.rb', <<~RUBY
|
|
32
|
+
Rails.application.config.active_record.yaml_column_permitted_classes = [
|
|
33
|
+
ActiveSupport::TimeWithZone,
|
|
34
|
+
ActiveSupport::TimeZone,
|
|
35
|
+
Time
|
|
36
|
+
]
|
|
37
|
+
RUBY
|
|
29
38
|
|
|
30
39
|
rake 'db:migrate db:test:prepare'
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe PaperTrailManager, 'authorization integration', versioning: true do
|
|
6
|
+
let(:entity) { FactoryBot.create(:entity, name: 'Test Entity', status: 'Active') }
|
|
7
|
+
|
|
8
|
+
before do
|
|
9
|
+
entity
|
|
10
|
+
entity.update(status: 'Updated')
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
after do
|
|
14
|
+
default = proc { true }
|
|
15
|
+
PaperTrailManager.allow_index_block = default
|
|
16
|
+
PaperTrailManager.allow_show_block = default
|
|
17
|
+
PaperTrailManager.allow_revert_block = default
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe 'index' do
|
|
21
|
+
context 'when not authorized' do
|
|
22
|
+
before do
|
|
23
|
+
PaperTrailManager.allow_index_when { |_controller| false }
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it 'redirects with an error flash' do
|
|
27
|
+
get changes_path
|
|
28
|
+
expect(response).to have_http_status(:redirect)
|
|
29
|
+
expect(flash[:error]).to eq('You do not have permission to list changes.')
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
describe 'show' do
|
|
35
|
+
context 'when not authorized' do
|
|
36
|
+
before do
|
|
37
|
+
PaperTrailManager.allow_show_when { |_controller, _version| false }
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it 'redirects with an error flash' do
|
|
41
|
+
get change_path(entity.versions.last)
|
|
42
|
+
expect(response).to have_http_status(:redirect)
|
|
43
|
+
expect(flash[:error]).to eq('You do not have permission to show that change.')
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
context 'when change does not exist' do
|
|
48
|
+
it 'redirects with an error flash' do
|
|
49
|
+
get change_path(id: 999999)
|
|
50
|
+
expect(response).to have_http_status(:redirect)
|
|
51
|
+
expect(flash[:error]).to eq('No such version.')
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
describe 'revert' do
|
|
57
|
+
context 'when not authorized' do
|
|
58
|
+
before do
|
|
59
|
+
PaperTrailManager.allow_revert_when { |_controller, _version| false }
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it 'redirects with an error flash' do
|
|
63
|
+
put change_path(entity.versions.last)
|
|
64
|
+
expect(response).to have_http_status(:redirect)
|
|
65
|
+
expect(flash[:error]).to eq('You do not have permission to revert this change.')
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
context 'when change does not exist' do
|
|
70
|
+
it 'redirects with an error flash' do
|
|
71
|
+
put change_path(id: 999999)
|
|
72
|
+
expect(response).to have_http_status(:redirect)
|
|
73
|
+
expect(flash[:error]).to eq('No such version.')
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
describe 'filtering by non-existent type' do
|
|
79
|
+
it 'returns an empty changes list' do
|
|
80
|
+
get changes_path(type: 'NonExistentModel')
|
|
81
|
+
expect(response.body).to include('No changes found')
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe PaperTrailManager, 'date range filtering', versioning: true do
|
|
6
|
+
let(:entity) { FactoryBot.create(:entity, name: 'Test Entity', status: 'Active') }
|
|
7
|
+
|
|
8
|
+
before do
|
|
9
|
+
entity
|
|
10
|
+
entity.update(status: 'Updated')
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
describe 'index with date filters' do
|
|
14
|
+
context 'with from parameter' do
|
|
15
|
+
it 'shows changes on or after the date' do
|
|
16
|
+
get changes_path(from: Date.today.to_s)
|
|
17
|
+
expect(response).to have_http_status(:ok)
|
|
18
|
+
expect(response.body).to have_tag('.change_row')
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'returns no changes for future date' do
|
|
22
|
+
get changes_path(from: (Date.today + 1).to_s)
|
|
23
|
+
expect(response.body).to include('No changes found')
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
context 'with to parameter' do
|
|
28
|
+
it 'shows changes on or before the date' do
|
|
29
|
+
get changes_path(to: Date.today.to_s)
|
|
30
|
+
expect(response).to have_http_status(:ok)
|
|
31
|
+
expect(response.body).to have_tag('.change_row')
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it 'returns no changes for past date' do
|
|
35
|
+
get changes_path(to: (Date.today - 1).to_s)
|
|
36
|
+
expect(response.body).to include('No changes found')
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
context 'with from and to combined' do
|
|
41
|
+
it 'shows changes within the range' do
|
|
42
|
+
get changes_path(from: Date.today.to_s, to: Date.today.to_s)
|
|
43
|
+
expect(response).to have_http_status(:ok)
|
|
44
|
+
expect(response.body).to have_tag('.change_row')
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
context 'combined with type filter' do
|
|
49
|
+
it 'respects both date and type filters' do
|
|
50
|
+
get changes_path(from: Date.today.to_s, type: 'Entity')
|
|
51
|
+
expect(response).to have_http_status(:ok)
|
|
52
|
+
expect(response.body).to have_tag('.change_item', text: /Entity/)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
context 'with invalid date' do
|
|
57
|
+
it 'ignores invalid from date gracefully' do
|
|
58
|
+
get changes_path(from: 'not-a-date')
|
|
59
|
+
expect(response).to have_http_status(:ok)
|
|
60
|
+
expect(response.body).to have_tag('.change_row')
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it 'ignores invalid to date gracefully' do
|
|
64
|
+
get changes_path(to: 'garbage')
|
|
65
|
+
expect(response).to have_http_status(:ok)
|
|
66
|
+
expect(response.body).to have_tag('.change_row')
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
context 'date filter form' do
|
|
71
|
+
it 'renders date inputs' do
|
|
72
|
+
get changes_path
|
|
73
|
+
expect(response.body).to have_tag('input[type="date"][name="from"]')
|
|
74
|
+
expect(response.body).to have_tag('input[type="date"][name="to"]')
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it 'preserves date values in form' do
|
|
78
|
+
get changes_path(from: '2026-01-01', to: '2026-12-31')
|
|
79
|
+
expect(response.body).to have_tag('input[name="from"][value="2026-01-01"]')
|
|
80
|
+
expect(response.body).to have_tag('input[name="to"][value="2026-12-31"]')
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -14,11 +14,11 @@ describe PaperTrailManager, versioning: true do
|
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
context 'with changes' do
|
|
17
|
-
let(:reimu) {
|
|
18
|
-
let(:flanchan) {
|
|
19
|
-
let(:sakuya) {
|
|
20
|
-
let(:kyuu_hachi) {
|
|
21
|
-
let!(:uinodouzu) {
|
|
17
|
+
let(:reimu) { FactoryBot.create(:entity, name: 'Miko Hakurei Reimu', status: 'Highly Responsive to Prayers') }
|
|
18
|
+
let(:flanchan) { FactoryBot.create(:entity, name: 'Flandre Scarlet', status: 'The Embodiment of Scarlet Devil') }
|
|
19
|
+
let(:sakuya) { FactoryBot.create(:entity, name: 'Sakuya Izayoi', status: 'Flowering Night') }
|
|
20
|
+
let(:kyuu_hachi) { FactoryBot.create(:platform, name: 'PC-9801', status: 'SUGOI!!1!') }
|
|
21
|
+
let!(:uinodouzu) { FactoryBot.create(:platform, name: 'Mikorusofto Uinodouzu', status: 'o-O') }
|
|
22
22
|
|
|
23
23
|
let!(:flanchan_id) { flanchan.id }
|
|
24
24
|
|
|
@@ -161,7 +161,7 @@ describe PaperTrailManager, versioning: true do
|
|
|
161
161
|
end
|
|
162
162
|
|
|
163
163
|
it 'rollbacks a delete by restoring the record' do
|
|
164
|
-
Entity.exists?(flanchan_id).
|
|
164
|
+
expect(Entity.exists?(flanchan_id)).to be_falsey
|
|
165
165
|
|
|
166
166
|
put change_path(PaperTrail::Version.where(item_id: flanchan_id, item_type: 'Entity').last)
|
|
167
167
|
|