paper_trail_viewer 1.0.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 +7 -0
- data/.github/workflows/test.yml +43 -0
- data/.gitignore +41 -0
- data/Appraisals +13 -0
- data/CHANGELOG.md +9 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +23 -0
- data/README.md +53 -0
- data/Rakefile +45 -0
- data/app/controllers/paper_trail_viewer/js_controller.rb +14 -0
- data/app/controllers/paper_trail_viewer/versions_controller.rb +119 -0
- data/app/controllers/paper_trail_viewer/viewer_controller.rb +4 -0
- data/app/views/paper_trail_viewer/viewer/index.html.erb +5 -0
- data/bin/setup +8 -0
- data/config/routes.rb +5 -0
- data/gemfiles/rails_6.0_paper_trail_11.1.gemfile +10 -0
- data/gemfiles/rails_6.0_paper_trail_12.2.gemfile +10 -0
- data/gemfiles/rails_7.0_paper_trail_12.2.gemfile +10 -0
- data/javascript/compiled.js +2 -0
- data/javascript/src/app.tsx +100 -0
- data/javascript/src/components/change_diff.tsx +57 -0
- data/javascript/src/components/config_modal.tsx +22 -0
- data/javascript/src/components/controls.tsx +62 -0
- data/javascript/src/components/full_object_modal.tsx +21 -0
- data/javascript/src/components/index.ts +3 -0
- data/javascript/src/components/modal.tsx +34 -0
- data/javascript/src/components/pagination.tsx +53 -0
- data/javascript/src/components/versions_list.tsx +142 -0
- data/javascript/src/index.ts +1 -0
- data/javascript/src/types.ts +42 -0
- data/lib/paper_trail_viewer/data_source/active_record.rb +30 -0
- data/lib/paper_trail_viewer/data_source/bigquery.rb +45 -0
- data/lib/paper_trail_viewer/engine.rb +5 -0
- data/lib/paper_trail_viewer/version.rb +3 -0
- data/lib/paper_trail_viewer.rb +11 -0
- data/package.json +43 -0
- data/paper_trail_viewer.gemspec +34 -0
- data/spec/app_template.rb +19 -0
- data/spec/rails_helper.rb +18 -0
- data/spec/support/factories.rb +13 -0
- data/spec/system/paper_trail_viewer_spec.rb +114 -0
- data/tsconfig.json +13 -0
- data/webpack.config.js +26 -0
- metadata +251 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 06cbe395c995ac810d7164e0efcc15786a545fd5abe4277a6c2e800ed2cb0ef4
|
4
|
+
data.tar.gz: 991c4f1ed961a5d8a5c5967d3b14c78534cdb549d6d7a235e3e38de634797e14
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: af134d7971dff9b4d2344c534aa47f61e4bcd52fa06bcba99e7336db544a50aa0e0ac262db3e03b44830a2df7cf517e9aa9c44e9ce2912c37c0342bf18eaf29b
|
7
|
+
data.tar.gz: 8508f49cf1d1267b793f20917ec7f52363ce186898f6d8c36827e50619387bff0eecb3ee2f5a9bfe9c9d47c5974cc03cef2edd32958e6a4d082da91b16467f11
|
@@ -0,0 +1,43 @@
|
|
1
|
+
name: Tests
|
2
|
+
|
3
|
+
on: [push, pull_request]
|
4
|
+
|
5
|
+
jobs:
|
6
|
+
test:
|
7
|
+
runs-on: ubuntu-latest
|
8
|
+
|
9
|
+
strategy:
|
10
|
+
fail-fast: false
|
11
|
+
matrix:
|
12
|
+
ruby:
|
13
|
+
- 2.7
|
14
|
+
- 3.0
|
15
|
+
gemfile:
|
16
|
+
- gemfiles/rails_6.0_paper_trail_11.1.gemfile
|
17
|
+
- gemfiles/rails_6.0_paper_trail_12.2.gemfile
|
18
|
+
- gemfiles/rails_7.0_paper_trail_12.2.gemfile
|
19
|
+
|
20
|
+
env:
|
21
|
+
BUNDLE_GEMFILE: ${{ matrix.gemfile }}
|
22
|
+
|
23
|
+
steps:
|
24
|
+
- uses: actions/checkout@v2
|
25
|
+
- uses: actions/setup-ruby@v1
|
26
|
+
with:
|
27
|
+
ruby-version: ${{ matrix.ruby }}
|
28
|
+
- uses: actions/cache@v1
|
29
|
+
with:
|
30
|
+
path: vendor/bundle
|
31
|
+
key: ${{ runner.os }}-${{ matrix.ruby}}-gems-${{ hashFiles('**/paper_trail_viewer.gemspec') }}
|
32
|
+
restore-keys: |
|
33
|
+
${{ runner.os }}-${{ matrix.ruby }}-gems-
|
34
|
+
- uses: actions/setup-node@v2
|
35
|
+
with:
|
36
|
+
node-version: '16'
|
37
|
+
# - uses: nanasess/setup-chromedriver@v1.0.1
|
38
|
+
- name: Install dependencies
|
39
|
+
run: |
|
40
|
+
bundle install --jobs 4 --retry 3
|
41
|
+
npm install
|
42
|
+
- name: Build
|
43
|
+
run: bundle exec rake
|
data/.gitignore
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
*.a
|
2
|
+
*.bundle
|
3
|
+
*.gem
|
4
|
+
*.gemfile.lock
|
5
|
+
*.iml
|
6
|
+
*.o
|
7
|
+
*.so
|
8
|
+
*.stTheme.cache
|
9
|
+
*.sublime-project
|
10
|
+
*.sublime-workspace
|
11
|
+
*.swp
|
12
|
+
*.tmPreferences.cache
|
13
|
+
*.tmlanguage.cache
|
14
|
+
*~
|
15
|
+
.DS_Store
|
16
|
+
.byebug_history
|
17
|
+
.idea/
|
18
|
+
.rspec_status
|
19
|
+
.ruby-gemset
|
20
|
+
.ruby-version
|
21
|
+
.tags
|
22
|
+
.tags1
|
23
|
+
.tool-versions
|
24
|
+
.vscode
|
25
|
+
/.bundle/
|
26
|
+
/.yardoc
|
27
|
+
/_yardoc/
|
28
|
+
/coverage/
|
29
|
+
/doc/
|
30
|
+
/javascript/compiled*
|
31
|
+
/node_modules
|
32
|
+
/pkg/
|
33
|
+
/spec/reports/
|
34
|
+
/tmp/
|
35
|
+
Gemfile.lock
|
36
|
+
bbin/
|
37
|
+
binstubs/*
|
38
|
+
bundler_stubs/*/.yardoc
|
39
|
+
mkmf.log
|
40
|
+
package-lock.json
|
41
|
+
spec/dummy
|
data/Appraisals
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
{
|
2
|
+
'6.0' => %w[11.1 12.2],
|
3
|
+
'7.0' => %w[12.2],
|
4
|
+
}.each do |rails_version, paper_trail_versions|
|
5
|
+
paper_trail_versions.each do |paper_trail_version|
|
6
|
+
appraise "rails-#{rails_version}-paper_trail-#{paper_trail_version}" do
|
7
|
+
gem 'rails', "~> #{rails_version}"
|
8
|
+
gem 'sqlite3', '~> 1.4'
|
9
|
+
gem 'paper_trail', "~> #{paper_trail_version}"
|
10
|
+
gem 'kaminari'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
# Changelog
|
2
|
+
All notable changes to this project will be documented in this file.
|
3
|
+
|
4
|
+
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
5
|
+
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
6
|
+
|
7
|
+
## [1.0.0] - 2022-03-26
|
8
|
+
|
9
|
+
Initial release.
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
Copyright for portions of paper_trail_viewer are held by Igal Koshevoy, 2011,
|
2
|
+
as part of project paper_trail_manager.
|
3
|
+
|
4
|
+
All other copyright for paper_trail_viewer is held by Janosch Müller, 2022.
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
7
|
+
a copy of this software and associated documentation files (the
|
8
|
+
"Software"), to deal in the Software without restriction, including
|
9
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
10
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
11
|
+
permit persons to whom the Software is furnished to do so, subject to
|
12
|
+
the following conditions:
|
13
|
+
|
14
|
+
The above copyright notice and this permission notice shall be
|
15
|
+
included in all copies or substantial portions of the Software.
|
16
|
+
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
18
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
19
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
20
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
21
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
22
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
23
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
[](http://badge.fury.io/rb/paper_trail_viewer)
|
2
|
+
[](https://github.com/jaynetics/paper_trail_viewer/actions)
|
3
|
+
|
4
|
+
# PaperTrailViewer
|
5
|
+
|
6
|
+
Browse changes to records when using Ruby on Rails and the [`paper_trail` gem](https://github.com/paper-trail-gem/paper_trail).
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
Add `paper_trail_viewer` to your bundle and add the following line to your `config/routes.rb`:
|
11
|
+
|
12
|
+
mount PaperTrailViewer::Engine => '/changes'
|
13
|
+
|
14
|
+
You can pick any path. Restart the server and go to the chosen path to view your versions.
|
15
|
+
|
16
|
+
To limit access to this view, do something like:
|
17
|
+
|
18
|
+
authenticate :user, ->*{ |u| u.superadmin? } do
|
19
|
+
mount PaperTrailViewer::Engine => '/changes'
|
20
|
+
end
|
21
|
+
|
22
|
+
### Configuration
|
23
|
+
|
24
|
+
Put configuration in `config/initializers/paper_trail_viewer.rb`.
|
25
|
+
|
26
|
+
E.g. for linking (or not) to the whodunnit user with a custom path helper:
|
27
|
+
|
28
|
+
PaperTrailViewer.user_path_method = :admin_path # default is :user_path
|
29
|
+
PaperTrailViewer.user_path_method = nil # don't link to the user
|
30
|
+
|
31
|
+
## Development
|
32
|
+
|
33
|
+
### Setup
|
34
|
+
|
35
|
+
* Clone the repository
|
36
|
+
* Go into the directory
|
37
|
+
* Run `bin/setup` to install Ruby and JS dependencies
|
38
|
+
|
39
|
+
### Running tests
|
40
|
+
|
41
|
+
* This repo uses the [Appraisal](https://github.com/thoughtbot/appraisal) gem
|
42
|
+
* Run `appraisal generate`
|
43
|
+
* Run `appraisal install`
|
44
|
+
* Run `appraisal rake generate_spec_app`
|
45
|
+
* Run `appraisal rake`
|
46
|
+
|
47
|
+
## License
|
48
|
+
|
49
|
+
This program is provided under an MIT open source license, read the [LICENSE.txt](https://github.com/jaynetics/paper_trail_viewer/blob/master/LICENSE.txt) file for details.
|
50
|
+
|
51
|
+
## To Note:
|
52
|
+
|
53
|
+
This project started as a fork of [PaperTrailManager](https://github.com/fusion94/paper_trail_manager), which was originally developed by [Igal Koshevoy](https://github.com/igal), [Reid Beels](https://github.com/reidab), and [Micah Geisel](https://github.com/botandrose).
|
data/Rakefile
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'bundler/gem_tasks'
|
3
|
+
require 'rubygems/package_task'
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
|
6
|
+
Bundler::GemHelper.install_tasks
|
7
|
+
|
8
|
+
RSpec::Core::RakeTask.new
|
9
|
+
task default: [:compile_js, :generate_spec_app, :spec]
|
10
|
+
|
11
|
+
task :compile_js do
|
12
|
+
`npm run compile`
|
13
|
+
end
|
14
|
+
|
15
|
+
task :generate_spec_app do
|
16
|
+
sh 'rm -rf spec/dummy'
|
17
|
+
sh *%w[
|
18
|
+
rails new spec/dummy
|
19
|
+
--template=spec/app_template.rb
|
20
|
+
--skip-action-cable
|
21
|
+
--skip-action-mailbox
|
22
|
+
--skip-action-mailer
|
23
|
+
--skip-action-text
|
24
|
+
--skip-active-job
|
25
|
+
--skip-active-storage
|
26
|
+
--skip-asset-pipeline
|
27
|
+
--skip-bootsnap
|
28
|
+
--skip-bundle
|
29
|
+
--skip-git
|
30
|
+
--skip-hotwire
|
31
|
+
--skip-javascript
|
32
|
+
--skip-jbuilder
|
33
|
+
--skip-keeps
|
34
|
+
--skip-listen
|
35
|
+
--skip-spring
|
36
|
+
--skip-sprockets
|
37
|
+
--skip-system-test
|
38
|
+
--skip-test
|
39
|
+
--skip-turbolinks
|
40
|
+
--skip-webpack
|
41
|
+
]
|
42
|
+
end
|
43
|
+
|
44
|
+
# ensure fresh js is compiled when packaging the gem
|
45
|
+
task build: [:compile_js]
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# This returns the pre-compiled JS for the viewer component.
|
2
|
+
# Yes, that is a hacky way to make the gem work without
|
3
|
+
# forcing users to install and integrate an npm package.
|
4
|
+
class PaperTrailViewer::JsController < ActionController::Base
|
5
|
+
protect_from_forgery unless: -> { request.format.js? }
|
6
|
+
|
7
|
+
def show
|
8
|
+
send_file js_file, type: 'text/javascript', disposition: 'inline'
|
9
|
+
end
|
10
|
+
|
11
|
+
def js_file
|
12
|
+
File.join(__dir__, '..', '..', '..', 'javascript', 'compiled.js')
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
class PaperTrailViewer::VersionsController < ActionController::Base
|
2
|
+
# Return the queried versions as JSON.
|
3
|
+
def index
|
4
|
+
query = sanitized_params
|
5
|
+
versions = PaperTrailViewer.data_source.call(**query)
|
6
|
+
versions_as_json = versions.map { |v| version_as_json(v) }
|
7
|
+
|
8
|
+
render json: {
|
9
|
+
hasNextPage: !versions.last_page? && versions_as_json.any?,
|
10
|
+
query: query,
|
11
|
+
versions: versions_as_json,
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
# Rollback a change
|
16
|
+
def update
|
17
|
+
unless version = PaperTrail::Version.find_by(id: params[:id])
|
18
|
+
flash[:error] = 'No such version.'
|
19
|
+
return redirect_to(root_url)
|
20
|
+
end
|
21
|
+
|
22
|
+
result =
|
23
|
+
if version.event == 'create'
|
24
|
+
version.item_type.constantize.find(version.item_id).destroy
|
25
|
+
else
|
26
|
+
version.reify.save
|
27
|
+
end
|
28
|
+
|
29
|
+
if result
|
30
|
+
if version.event == 'create'
|
31
|
+
flash[:notice] = 'Rolled back newly-created record by destroying it.'
|
32
|
+
redirect_to root_url
|
33
|
+
else
|
34
|
+
flash[:notice] = 'Rolled back changes to this record.'
|
35
|
+
redirect_to change_item_url(version)
|
36
|
+
end
|
37
|
+
else
|
38
|
+
flash[:error] = "Couldn't rollback. Sorry."
|
39
|
+
redirect_to root_url
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def sanitized_params
|
46
|
+
{
|
47
|
+
event: params[:event].presence_in(%w[create update destroy]),
|
48
|
+
filter: (params[:filter].presence if params[:filter] != '%%'),
|
49
|
+
item_id: params[:item_id].presence,
|
50
|
+
item_type: params[:item_type].presence,
|
51
|
+
page: (page = params[:page].to_i) > 0 ? page : 1,
|
52
|
+
per_page: (per = params[:per_page].to_i).clamp(1, 1000),
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
def version_as_json(version)
|
57
|
+
{
|
58
|
+
**version.attributes.slice(*%w[id whodunnit event created_at]),
|
59
|
+
changeset: changeset_for(version),
|
60
|
+
object: load_object(version),
|
61
|
+
item_id: version.item_id.to_s,
|
62
|
+
item_type: version.item_type,
|
63
|
+
item_url: change_item_url(version),
|
64
|
+
user_url: user_url(version),
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
def changeset_for(version)
|
69
|
+
case version.event
|
70
|
+
when 'create', 'update'
|
71
|
+
version.changeset || {}
|
72
|
+
when 'destroy'
|
73
|
+
record = version.reify rescue nil
|
74
|
+
return {} unless record
|
75
|
+
|
76
|
+
record.attributes.each_with_object({}) do |changes, (k, v)|
|
77
|
+
changes[k] = [v, nil] unless v.nil?
|
78
|
+
end
|
79
|
+
else
|
80
|
+
raise ArgumentError, "Unknown event: #{version.event}"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Return the URL for the item represented by the +version+,
|
85
|
+
# e.g. a Company record instance referenced by a version.
|
86
|
+
def change_item_url(version)
|
87
|
+
version_type = version.item_type.underscore.split('/').last
|
88
|
+
main_app.try("#{version_type}_url", version.item_id)
|
89
|
+
end
|
90
|
+
|
91
|
+
def user_url(version)
|
92
|
+
(path_method = PaperTrailViewer.user_path_method).present? &&
|
93
|
+
(id = version.whodunnit).present? &&
|
94
|
+
!id.start_with?('#') &&
|
95
|
+
main_app.try(path_method, id) ||
|
96
|
+
nil
|
97
|
+
end
|
98
|
+
|
99
|
+
def load_object(version)
|
100
|
+
obj = version.object
|
101
|
+
if obj.is_a?(String)
|
102
|
+
PaperTrail.serializer.load(obj)
|
103
|
+
elsif obj.is_a?(Hash)
|
104
|
+
OpenStruct.new(obj)
|
105
|
+
else
|
106
|
+
obj
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# backport deserialization fix for recent rubies
|
112
|
+
# https://github.com/paper-trail-gem/paper_trail/pull/1338
|
113
|
+
if PaperTrail::VERSION.to_s < '12.2.0'
|
114
|
+
module PaperTrail::Serializers::YAML
|
115
|
+
def load(string)
|
116
|
+
::YAML.respond_to?(:unsafe_load) ? ::YAML.unsafe_load(string) : ::YAML.load(string)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
data/bin/setup
ADDED
data/config/routes.rb
ADDED