├── .github └── workflows │ └── build.yml ├── .gitignore ├── CHANGELOG ├── Gemfile ├── Gemfile-dev ├── Gemfile.lock ├── MIT-LICENSE ├── README.md ├── Rakefile ├── app ├── assets │ └── stylesheets │ │ └── audit-log │ │ └── application.css ├── controllers │ └── audit_log │ │ └── logs_controller.rb ├── models │ └── audit_log │ │ └── log.rb └── views │ ├── audit_log │ └── logs │ │ ├── index.html.erb │ │ └── show.html.erb │ └── layouts │ └── audit-log │ └── application.html.erb ├── audit-log.gemspec ├── bin ├── rails └── test ├── config ├── initializers │ └── audit-log.rb ├── locales │ └── audit-log.yml └── routes.rb ├── db └── migrate │ └── 20190527035005_create_audit_logs.rb ├── gemfiles ├── Gemfile-5-2 └── Gemfile-6-0 ├── lib ├── audit-log.rb ├── audit-log │ ├── configuration.rb │ ├── controller_helper.rb │ ├── engine.rb │ ├── log_subscriber.rb │ ├── model.rb │ └── version.rb └── generators │ └── audit_log │ └── install_generator.rb └── test ├── controllers └── navigation_test.rb ├── dummy ├── .gitignore ├── Gemfile ├── Gemfile.lock ├── Rakefile ├── app │ ├── assets │ │ ├── config │ │ │ └── manifest.js │ │ ├── images │ │ │ └── .keep │ │ ├── javascripts │ │ │ └── application.js │ │ └── stylesheets │ │ │ ├── application.scss │ │ │ ├── notifications.scss │ │ │ └── scaffolds.scss │ ├── controllers │ │ ├── application_controller.rb │ │ ├── comments_controller.rb │ │ ├── concerns │ │ │ └── .keep │ │ ├── topics_controller.rb │ │ └── welcome_controller.rb │ ├── helpers │ │ ├── application_helper.rb │ │ ├── comments_helper.rb │ │ └── topics_helper.rb │ ├── mailers │ │ └── .keep │ ├── models │ │ ├── .keep │ │ ├── application_record.rb │ │ ├── comment.rb │ │ ├── concerns │ │ │ └── .keep │ │ ├── topic.rb │ │ └── user.rb │ └── views │ │ ├── comments │ │ ├── _form.html.erb │ │ ├── edit.html.erb │ │ ├── index.html.erb │ │ ├── new.html.erb │ │ └── show.html.erb │ │ ├── layouts │ │ └── application.html.erb │ │ ├── notifications │ │ ├── _comment.html.erb │ │ └── _new_topic.html.erb │ │ ├── topics │ │ ├── _form.html.erb │ │ ├── edit.html.erb │ │ ├── index.html.erb │ │ ├── new.html.erb │ │ └── show.html.erb │ │ └── welcome │ │ └── index.html.erb ├── bin │ ├── bundle │ ├── rails │ ├── rake │ ├── setup │ └── update ├── config.ru ├── config │ ├── application.rb │ ├── boot.rb │ ├── cable.yml │ ├── database.yml │ ├── environment.rb │ ├── environments │ │ ├── development.rb │ │ ├── production.rb │ │ └── test.rb │ ├── initializers │ │ ├── application_controller_renderer.rb │ │ ├── assets.rb │ │ ├── audit-log.rb │ │ ├── backtrace_silencers.rb │ │ ├── cookies_serializer.rb │ │ ├── devise.rb │ │ ├── filter_parameter_logging.rb │ │ ├── inflections.rb │ │ ├── mime_types.rb │ │ ├── session_store.rb │ │ └── wrap_parameters.rb │ ├── locales │ │ ├── devise.en.yml │ │ └── en.yml │ ├── puma.rb │ ├── routes.rb │ ├── secrets.yml │ └── spring.rb ├── db │ ├── migrate │ │ ├── 20160321143003_devise_create_users.rb │ │ ├── 20160328070223_create_topics.rb │ │ └── 20160328070302_create_comments.rb │ ├── schema.rb │ └── seeds.rb ├── lib │ ├── assets │ │ └── .keep │ └── tasks │ │ └── .keep ├── log │ └── .keep ├── public │ ├── 404.html │ ├── 422.html │ ├── 500.html │ ├── favicon.ico │ └── robots.txt └── vendor │ └── assets │ ├── javascripts │ └── .keep │ └── stylesheets │ └── .keep ├── factories ├── comments.rb ├── logs.rb ├── topics.rb └── users.rb ├── lib └── audit_log_test.rb ├── models └── log_test.rb └── test_helper.rb /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | on: push 3 | jobs: 4 | build: 5 | if: "!contains(github.event.head_commit.message, '[skip ci]')" 6 | runs-on: ubuntu-latest 7 | strategy: 8 | fail-fast: false 9 | matrix: 10 | include: 11 | - ruby: 3.0.0 12 | gemfile: Gemfile 13 | postgres: 10 14 | - ruby: 2.7 15 | gemfile: gemfiles/Gemfile-6-0 16 | postgres: 10 17 | - ruby: 2.6 18 | gemfile: gemfiles/Gemfile-5-2 19 | postgres: 10 20 | env: 21 | BUNDLE_GEMFILE: ${{ matrix.gemfile }} 22 | USE_OFFICIAL_GEM_SOURCE: 1 23 | steps: 24 | - uses: actions/checkout@v2 25 | - uses: ruby/setup-ruby@v1 26 | with: 27 | ruby-version: ${{ matrix.ruby }} 28 | bundler-cache: true 29 | - uses: ankane/setup-postgres@v1 30 | with: 31 | postgres-version: ${{ matrix.postgres }} 32 | - run: bundle exec rails db:create db:migrate 33 | - run: bundle exec rails test 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .bundle/ 2 | log/*.log 3 | pkg/ 4 | gemfiles/*.lock 5 | test/dummy/db/*.sqlite3 6 | test/dummy/db/*.sqlite3-journal 7 | test/dummy/log/*.log 8 | test/dummy/tmp/ 9 | coverage/ 10 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | 1.1.0 2 | ----- 3 | 4 | - Requirement Rails >= 5.2. 5 | - Fix audit_logs primary key for use `bigint` column type. 6 | - Fix migration for use `bigint` column type. 7 | 8 | 1.0.0 9 | ----- 10 | 11 | - Use custom debug log for instead of the SQL log, for avoid output too much line of logs. 12 | 13 | 0.3.2 14 | ----- 15 | 16 | - Fix assets.precompile config. 17 | 18 | 0.3.1 19 | ----- 20 | 21 | * Fix `audit!` method to use `request.remote_ip` to instead of `request.ip` for get real ip. 22 | 23 | 0.3.0 24 | ----- 25 | 26 | - Fix `action_options` for translations load. 27 | 28 | 0.2.0 29 | ----- 30 | 31 | - Fix `audit!` for avoid create a new record, when assign argument have a new record model instance. 32 | - Add `AuditLog.action_options` for get select options. 33 | - Generate `config/locales/audit-log.yml` for write I18n. 34 | 35 | 0.1.1 36 | ----- 37 | 38 | - Fix for Rails 5.0 support. 39 | 40 | 0.1.0 41 | ----- 42 | 43 | - First release. 44 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source "https://rubygems.org" 4 | git_source(:github) { |repo| "https://github.com/#{repo}.git" } 5 | 6 | gemspec 7 | 8 | gem "rails", "6.1.0" 9 | eval File.read(File.expand_path("Gemfile-dev", __dir__)), nil, "Gemfile-dev" 10 | -------------------------------------------------------------------------------- /Gemfile-dev: -------------------------------------------------------------------------------- 1 | gem "sass-rails" 2 | gem "uglifier" 3 | gem "coffee-rails" 4 | gem "devise" 5 | gem "jquery-rails" 6 | gem "pg" 7 | gem "puma" 8 | gem "bootstrap" 9 | 10 | group :development, :test do 11 | gem "minitest" 12 | gem "factory_bot" 13 | end 14 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | audit-log (1.2.0) 5 | kaminari (>= 0.15) 6 | rails (>= 5.2) 7 | 8 | GEM 9 | remote: https://rubygems.org/ 10 | specs: 11 | actioncable (6.1.0) 12 | actionpack (= 6.1.0) 13 | activesupport (= 6.1.0) 14 | nio4r (~> 2.0) 15 | websocket-driver (>= 0.6.1) 16 | actionmailbox (6.1.0) 17 | actionpack (= 6.1.0) 18 | activejob (= 6.1.0) 19 | activerecord (= 6.1.0) 20 | activestorage (= 6.1.0) 21 | activesupport (= 6.1.0) 22 | mail (>= 2.7.1) 23 | actionmailer (6.1.0) 24 | actionpack (= 6.1.0) 25 | actionview (= 6.1.0) 26 | activejob (= 6.1.0) 27 | activesupport (= 6.1.0) 28 | mail (~> 2.5, >= 2.5.4) 29 | rails-dom-testing (~> 2.0) 30 | actionpack (6.1.0) 31 | actionview (= 6.1.0) 32 | activesupport (= 6.1.0) 33 | rack (~> 2.0, >= 2.0.9) 34 | rack-test (>= 0.6.3) 35 | rails-dom-testing (~> 2.0) 36 | rails-html-sanitizer (~> 1.0, >= 1.2.0) 37 | actiontext (6.1.0) 38 | actionpack (= 6.1.0) 39 | activerecord (= 6.1.0) 40 | activestorage (= 6.1.0) 41 | activesupport (= 6.1.0) 42 | nokogiri (>= 1.8.5) 43 | actionview (6.1.0) 44 | activesupport (= 6.1.0) 45 | builder (~> 3.1) 46 | erubi (~> 1.4) 47 | rails-dom-testing (~> 2.0) 48 | rails-html-sanitizer (~> 1.1, >= 1.2.0) 49 | activejob (6.1.0) 50 | activesupport (= 6.1.0) 51 | globalid (>= 0.3.6) 52 | activemodel (6.1.0) 53 | activesupport (= 6.1.0) 54 | activerecord (6.1.0) 55 | activemodel (= 6.1.0) 56 | activesupport (= 6.1.0) 57 | activestorage (6.1.0) 58 | actionpack (= 6.1.0) 59 | activejob (= 6.1.0) 60 | activerecord (= 6.1.0) 61 | activesupport (= 6.1.0) 62 | marcel (~> 0.3.1) 63 | mimemagic (~> 0.3.2) 64 | activesupport (6.1.0) 65 | concurrent-ruby (~> 1.0, >= 1.0.2) 66 | i18n (>= 1.6, < 2) 67 | minitest (>= 5.1) 68 | tzinfo (~> 2.0) 69 | zeitwerk (~> 2.3) 70 | autoprefixer-rails (10.4.7.0) 71 | execjs (~> 2) 72 | bcrypt (3.1.18) 73 | bootstrap (5.1.3) 74 | autoprefixer-rails (>= 9.1.0) 75 | popper_js (>= 2.9.3, < 3) 76 | sassc-rails (>= 2.0.0) 77 | builder (3.2.4) 78 | coffee-rails (5.0.0) 79 | coffee-script (>= 2.2.0) 80 | railties (>= 5.2.0) 81 | coffee-script (2.4.1) 82 | coffee-script-source 83 | execjs 84 | coffee-script-source (1.12.2) 85 | concurrent-ruby (1.1.10) 86 | crass (1.0.6) 87 | devise (4.8.1) 88 | bcrypt (~> 3.0) 89 | orm_adapter (~> 0.1) 90 | railties (>= 4.1.0) 91 | responders 92 | warden (~> 1.2.3) 93 | erubi (1.10.0) 94 | execjs (2.8.1) 95 | factory_bot (6.2.1) 96 | activesupport (>= 5.0.0) 97 | ffi (1.15.5) 98 | globalid (1.0.0) 99 | activesupport (>= 5.0) 100 | i18n (1.10.0) 101 | concurrent-ruby (~> 1.0) 102 | jquery-rails (4.5.0) 103 | rails-dom-testing (>= 1, < 3) 104 | railties (>= 4.2.0) 105 | thor (>= 0.14, < 2.0) 106 | kaminari (1.2.2) 107 | activesupport (>= 4.1.0) 108 | kaminari-actionview (= 1.2.2) 109 | kaminari-activerecord (= 1.2.2) 110 | kaminari-core (= 1.2.2) 111 | kaminari-actionview (1.2.2) 112 | actionview 113 | kaminari-core (= 1.2.2) 114 | kaminari-activerecord (1.2.2) 115 | activerecord 116 | kaminari-core (= 1.2.2) 117 | kaminari-core (1.2.2) 118 | loofah (2.18.0) 119 | crass (~> 1.0.2) 120 | nokogiri (>= 1.5.9) 121 | mail (2.7.1) 122 | mini_mime (>= 0.1.1) 123 | marcel (0.3.3) 124 | mimemagic (~> 0.3.2) 125 | method_source (1.0.0) 126 | mimemagic (0.3.10) 127 | nokogiri (~> 1) 128 | rake 129 | mini_mime (1.1.2) 130 | mini_portile2 (2.8.0) 131 | minitest (5.16.1) 132 | nio4r (2.5.8) 133 | nokogiri (1.13.6) 134 | mini_portile2 (~> 2.8.0) 135 | racc (~> 1.4) 136 | orm_adapter (0.5.0) 137 | pg (1.4.1) 138 | popper_js (2.9.3) 139 | puma (5.6.4) 140 | nio4r (~> 2.0) 141 | racc (1.6.0) 142 | rack (2.2.3.1) 143 | rack-test (2.0.2) 144 | rack (>= 1.3) 145 | rails (6.1.0) 146 | actioncable (= 6.1.0) 147 | actionmailbox (= 6.1.0) 148 | actionmailer (= 6.1.0) 149 | actionpack (= 6.1.0) 150 | actiontext (= 6.1.0) 151 | actionview (= 6.1.0) 152 | activejob (= 6.1.0) 153 | activemodel (= 6.1.0) 154 | activerecord (= 6.1.0) 155 | activestorage (= 6.1.0) 156 | activesupport (= 6.1.0) 157 | bundler (>= 1.15.0) 158 | railties (= 6.1.0) 159 | sprockets-rails (>= 2.0.0) 160 | rails-dom-testing (2.0.3) 161 | activesupport (>= 4.2.0) 162 | nokogiri (>= 1.6) 163 | rails-html-sanitizer (1.4.3) 164 | loofah (~> 2.3) 165 | railties (6.1.0) 166 | actionpack (= 6.1.0) 167 | activesupport (= 6.1.0) 168 | method_source 169 | rake (>= 0.8.7) 170 | thor (~> 1.0) 171 | rake (13.0.6) 172 | responders (3.0.1) 173 | actionpack (>= 5.0) 174 | railties (>= 5.0) 175 | sass-rails (6.0.0) 176 | sassc-rails (~> 2.1, >= 2.1.1) 177 | sassc (2.4.0) 178 | ffi (~> 1.9) 179 | sassc-rails (2.1.2) 180 | railties (>= 4.0.0) 181 | sassc (>= 2.0) 182 | sprockets (> 3.0) 183 | sprockets-rails 184 | tilt 185 | sprockets (4.1.1) 186 | concurrent-ruby (~> 1.0) 187 | rack (> 1, < 3) 188 | sprockets-rails (3.4.2) 189 | actionpack (>= 5.2) 190 | activesupport (>= 5.2) 191 | sprockets (>= 3.0.0) 192 | thor (1.2.1) 193 | tilt (2.0.10) 194 | tzinfo (2.0.4) 195 | concurrent-ruby (~> 1.0) 196 | uglifier (4.2.0) 197 | execjs (>= 0.3.0, < 3) 198 | warden (1.2.9) 199 | rack (>= 2.0.9) 200 | websocket-driver (0.7.5) 201 | websocket-extensions (>= 0.1.0) 202 | websocket-extensions (0.1.5) 203 | zeitwerk (2.6.0) 204 | 205 | PLATFORMS 206 | ruby 207 | 208 | DEPENDENCIES 209 | audit-log! 210 | bootstrap 211 | coffee-rails 212 | devise 213 | factory_bot 214 | jquery-rails 215 | minitest 216 | pg 217 | puma 218 | rails (= 6.1.0) 219 | sass-rails 220 | uglifier 221 | 222 | BUNDLED WITH 223 | 2.1.4 224 | -------------------------------------------------------------------------------- /MIT-LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2019 Jason Lee 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AuditLog 2 | 3 | [![build](https://github.com/rails-engine/audit-log/actions/workflows/build.yml/badge.svg)](https://github.com/rails-engine/audit-log/actions/workflows/build.yml) 4 | 5 | Trail audit logs (Operation logs) into the database for user behaviors, including a Web UI to query logs. 6 | 7 | > We used audit-log in our production environment more than 1 year, until now (2020.5.21), it's inserted about **20 million** log in our system. 8 | 9 | [中文介绍与使用说明](https://ruby-china.org/topics/39890) 10 | 11 | ## Demo UI 12 | 13 | Audit log list: 14 | 15 | 16 | 17 | Detail page: 18 | 19 | 20 | 21 | 22 | ## Installation 23 | 24 | Add this line to your application's Gemfile: 25 | 26 | ```ruby 27 | gem "audit-log" 28 | ``` 29 | 30 | And then execute: 31 | ```bash 32 | $ bundle 33 | ``` 34 | 35 | Generate files: 36 | 37 | ```bash 38 | $ rails g audit_log:install 39 | ``` 40 | 41 | ## Usage 42 | 43 | Use in controllers: 44 | 45 | ```rb 46 | class TicktsController < ApplicationController 47 | def index 48 | audit! :list_ticket, nil 49 | end 50 | 51 | def create 52 | if @ticket.save 53 | audit! :create_ticket, @ticket, payload: ticket_params 54 | else 55 | render :new 56 | end 57 | end 58 | 59 | def update 60 | if @ticket.save 61 | audit! :update_ticket, @ticket, payload: ticket_params 62 | else 63 | render :edit 64 | end 65 | end 66 | 67 | def approve 68 | if @ticket.approve 69 | audit! :approve_ticket, @ticket, payload: ticket_params 70 | end 71 | end 72 | 73 | def destroy 74 | # store original attributes for destroy for keep values 75 | audit! :delete_ticket, nil, @ticket.attributes 76 | end 77 | 78 | private 79 | 80 | def ticket_params 81 | params.required(:ticket).permit!(:title, :description, :status) 82 | end 83 | end 84 | ``` 85 | 86 | In models or other places: 87 | 88 | ```rb 89 | AuditLog.audit!(:update_password, @user, payload: { ip: request.remote_ip }) 90 | AuditLog.audit!(:sign_in, @user, payload: { ip: request.remote_ip }) 91 | AuditLog.audit!(:create_address, nil, payload: params) 92 | ``` 93 | 94 | Change `config/routes.rb` to add Route: 95 | 96 | ```rb 97 | Rails.application.routes.draw do 98 | authenticate :user, -> (u) { u.admin? } do 99 | mount AuditLog::Engine => "/audit-log" 100 | end 101 | end 102 | ``` 103 | 104 | I18n for audit names, you need create a `config/locales/audit-log.zh-CN.yml`: 105 | 106 | ```yml 107 | zh-CN: 108 | audit_log: 109 | action: 110 | sign_in: 登录 111 | update_password: 修改密码 112 | create_address: 添加住址 113 | list_ticket: 查看工单列表 114 | create_ticket: 创建工单 115 | update_ticket: 更新工单 116 | delete_ticket: 删除工单 117 | approve_ticket: 审批工单 118 | ``` 119 | 120 | For track Warden (Devise) sign in behavirs: 121 | 122 | config/initializes/devise.rb 123 | 124 | ```rb 125 | Warden::Manager.after_authentication do |user, auth, opts| 126 | request = ActionDispatch::Request.new(auth.env) 127 | AuditLog.audit!(:sign_in, user, payload: opts, user: user, request: request) 128 | end 129 | 130 | Warden::Manager.before_failure do |env, opts| 131 | request = ActionDispatch::Request.new(env) 132 | email = request.params.dig(:user, :email) 133 | user = User.find_by_email(email) 134 | opts[:email] = email 135 | AuditLog.audit!(:sign_in_failure, nil, payload: opts, request: request, user: user) 136 | end 137 | ``` 138 | 139 | ## Configuration 140 | 141 | You can write a `config/initializers/audit_log.rb` to configure the behavior of audit log. 142 | 143 | ```rb 144 | AuditLog.configure do 145 | # class name of you User model, default: 'User' 146 | self.user_class = "User" 147 | # current_user method name in your Controller, default: 'current_user' 148 | self.current_user_method = "current_user" 149 | # Speical a table_name for AuditLog model, default: "audit_logs" 150 | self.table_name = "audit_logs" 151 | end 152 | ``` 153 | 154 | ## License 155 | 156 | The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). 157 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | begin 4 | require "bundler/setup" 5 | rescue LoadError 6 | puts "You must `gem install bundler` and `bundle install` to run rake tasks" 7 | end 8 | 9 | require "rdoc/task" 10 | 11 | RDoc::Task.new(:rdoc) do |rdoc| 12 | rdoc.rdoc_dir = "rdoc" 13 | rdoc.title = "AuditLog" 14 | rdoc.options << "--line-numbers" 15 | rdoc.rdoc_files.include("README.md") 16 | rdoc.rdoc_files.include("lib/**/*.rb") 17 | end 18 | 19 | APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__) 20 | load "rails/tasks/engine.rake" 21 | 22 | load "rails/tasks/statistics.rake" 23 | 24 | require "bundler/gem_tasks" 25 | 26 | require "rake/testtask" 27 | 28 | Rake::TestTask.new(:test) do |t| 29 | t.libs << "lib" 30 | t.libs << "test" 31 | t.pattern = "test/**/*_test.rb" 32 | t.verbose = false 33 | end 34 | 35 | task default: :test 36 | -------------------------------------------------------------------------------- /app/assets/stylesheets/audit-log/application.css: -------------------------------------------------------------------------------- 1 | 2 | body { 3 | margin: 0; 4 | padding: 20px 0; 5 | background-color: #eee; 6 | } 7 | 8 | body, textarea { 9 | font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, Helvetica, sans-serif; 10 | font-size: 14px; 11 | line-height: 1.4; 12 | color: #333; 13 | } 14 | 15 | .footer { 16 | padding: 15px; 17 | text-align: center; 18 | color: #999; 19 | } 20 | .footer a:link, 21 | .footer a:visited { color: #666; text-decoration: underline;} 22 | 23 | a, a:visited, a:active { 24 | color: #364cc9; 25 | text-decoration: none; 26 | } 27 | 28 | a:hover { 29 | text-decoration: underline; 30 | } 31 | 32 | table { 33 | width: 100%; 34 | border-collapse: collapse; 35 | border-spacing: 0; 36 | margin-bottom: 20px; 37 | } 38 | 39 | th { 40 | text-align: left; 41 | border-bottom: solid 1px #e0e0e0; 42 | } 43 | 44 | td.date { width: 150px; font-size: 12px; } 45 | 46 | h1 { 47 | margin-top: 0; 48 | font-size: 20px; 49 | font-weight: bold; 50 | } 51 | 52 | h1, p { 53 | margin-bottom: 20px; 54 | } 55 | 56 | h3 { 57 | text-align: center; 58 | } 59 | 60 | ul { 61 | list-style-type: none; 62 | padding: 0; 63 | margin: 0; 64 | } 65 | 66 | table td, table th { 67 | padding: 10px 15px; 68 | } 69 | th { background: #f5f5f5; border-bottom: 1px solid #e0e0e0; } 70 | td { 71 | border-top: solid 1px #e0e0e0; 72 | } 73 | 74 | pre { 75 | background-color: #eee; 76 | padding: 10px; 77 | white-space: pre-wrap; 78 | word-break: break-word; 79 | } 80 | 81 | textarea { 82 | width: 100%; 83 | height: 100px; 84 | border: solid 1px #ddd; 85 | padding: 10px; 86 | } 87 | 88 | hr { 89 | border: none; 90 | height: 0; 91 | border-top: solid 1px #ddd; 92 | margin-bottom: 15px; 93 | } 94 | 95 | .btn { 96 | display: inline-block; 97 | margin-bottom: 0; 98 | font-size: 14px; 99 | font-weight: 400; 100 | line-height: 1.42857143; 101 | text-align: center; 102 | white-space: nowrap; 103 | vertical-align: middle; 104 | cursor: pointer; 105 | -webkit-user-select: none; 106 | -moz-user-select: none; 107 | -ms-user-select: none; 108 | user-select: none; 109 | border-radius: 3px; 110 | border: 1px solid #ccc; 111 | padding: 6px 16px; 112 | color: #555 !important; 113 | outline: 0 !important; 114 | background: #FFF; 115 | } 116 | .btn:hover { text-decoration: none !important; background: #f7f7f7; } 117 | .btn-danger { background: #fff; color: #E33F00 !important; border-color: #E33F00;} 118 | .btn-danger:hover { 119 | background: #FCEDEC; 120 | } 121 | 122 | .form-control { 123 | font-size: 14px; 124 | line-height: 1.42857143; 125 | border: 1px solid #ccc; 126 | padding: 6px 16px; 127 | outline: 0 !important; 128 | border-radius: 3px; 129 | } 130 | .container { 131 | max-width: 1000px; 132 | margin-left: auto; 133 | margin-right: auto; 134 | padding: 20px; 135 | background-color: #fff; 136 | box-shadow: 0 1px 8px rgba(200, 200, 200, 0.26); 137 | border-radius: 3px; 138 | } 139 | 140 | .no-record { 141 | padding: 50px; 142 | text-align: center; 143 | font-size: 16px; 144 | } 145 | 146 | .toolbar { 147 | margin-bottom: 15px; 148 | height: 34px; 149 | line-height: 34px; 150 | } 151 | .toolbar form { display: inline; } 152 | .toolbar .pull-right { float: right; } 153 | 154 | #notice { 155 | padding: 8px 15px; 156 | background: #3CBD46; 157 | color: #fff; 158 | margin-bottom: 15px; 159 | border-radius: 3px; 160 | } 161 | 162 | pre { 163 | background: #f7f7f7; 164 | padding: 8px; 165 | border-radius: 3px; 166 | font-size: 12px; 167 | font-family: Menlo, Monaco, Consolas, monospace; 168 | } 169 | 170 | h1 { font-size: 16px; } 171 | 172 | .pagination { 173 | padding-bottom: 15px; 174 | font-size: 14px; 175 | } 176 | 177 | .pagination li { display: inline; } 178 | 179 | .pagination a { 180 | display: inline-block; 181 | padding: 5px 10px; 182 | border: 1px solid #eee; 183 | color: #555; 184 | text-decoration: none; 185 | } 186 | .pagination a:hover { 187 | background: #f7f7f7; 188 | } 189 | .pagination em, 190 | .pagination .current { 191 | display: inline-block; 192 | padding: 5px 10px; 193 | border: 1px solid #f0f0f0; 194 | background: #f0f0f0; 195 | font-style: normal; 196 | } 197 | 198 | .detail-group { 199 | margin-bottom: 8px; 200 | } 201 | .detail-group .control-label { 202 | width: 120px; 203 | color: #777; 204 | display: inline-block; 205 | } -------------------------------------------------------------------------------- /app/controllers/audit_log/logs_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module AuditLog 4 | class LogsController < ActionController::Base 5 | layout "audit-log/application" 6 | before_action :set_log, only: %i[show destroy] 7 | 8 | def index 9 | @logs = Log.order("id desc").includes(:user) 10 | @logs = @logs.where("action like ?", "%#{params[:q]}%") if params[:q].present? 11 | @logs = @logs.where("action = ?", params[:action_type]) if params[:action_type].present? 12 | @logs = @logs.where("created_at >= ?", Time.parse(params[:start_time])) if params[:start_time].present? 13 | @logs = @logs.where("created_at < ?", Time.parse(params[:end_time])) if params[:end_time].present? 14 | @logs = @logs.page(params[:page]).per(15) 15 | end 16 | 17 | def show; end 18 | 19 | private 20 | 21 | # Use callbacks to share common setup or constraints between actions. 22 | def set_log 23 | @log = Log.find(params[:id]) 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /app/models/audit_log/log.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module AuditLog 4 | class Log < ActiveRecord::Base 5 | include AuditLog::Model 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /app/views/audit_log/logs/index.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | <%= select_tag(:action_type, options_for_select(AuditLog.action_options, params[:action_type]), include_blank: "All actions", class: "form-control") %> 5 |
6 | 7 |
8 | 9 |
10 | 11 |
12 | 13 |
14 |
15 |
16 | <% if @logs.blank? %> 17 |
No audit logs.
18 | <% else %> 19 | <%= paginate @logs %> 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | <% @logs.each do |log| %> 34 | 35 | 36 | 37 | 38 | 39 | 42 | 43 | <% end %> 44 | 45 |
#UserAction
<%= log.id %><%= log.user_name %><%= log.action_name %><%= log.created_at.to_s %> 40 | <%= link_to "View", audit_log.log_path(log.id) %> 41 |
46 | 47 | <%= paginate @logs %> 48 | <% end %> 49 | -------------------------------------------------------------------------------- /app/views/audit_log/logs/show.html.erb: -------------------------------------------------------------------------------- 1 |
2 | <%= link_to 'Back', logs_path, class: 'btn' %> 3 |
4 | 5 |
6 |

<%= @log.action_name %>

7 | 8 |
9 | 10 | <%= @log.user_name %> 11 |
12 | 13 |
14 | 15 | <%= @log.created_at %> 16 |
17 | 18 |
19 | 20 | <%= @log.request["url"] %> 21 |
22 | 23 |
24 | 25 | <%= @log.request["ip"] %> 26 |
27 | 28 |
29 | 30 | <%= @log.request["user_agent"] %> 31 |
32 | 33 |

Payload

34 |
<%= JSON.pretty_generate(@log.payload) %>
35 | 36 | <% if @log.record %> 37 |

Record

38 |
<%= JSON.pretty_generate(@log.record.as_json) %>
39 | <% end %> 40 | 41 | 42 | -------------------------------------------------------------------------------- /app/views/layouts/audit-log/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Audit Log 5 | <%= stylesheet_link_tag "audit-log/application", media: "all" %> 6 | <%= csrf_meta_tags %> 7 | 8 | 9 | 10 |
11 | <% if notice %> 12 |
<%= notice %>
13 | <% end %> 14 | 15 | <%= yield %> 16 |
17 | 18 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /audit-log.gemspec: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | $LOAD_PATH.push File.expand_path("lib", __dir__) 4 | 5 | # Maintain your gem's version: 6 | require "audit-log/version" 7 | 8 | # Describe your gem and declare its dependencies: 9 | Gem::Specification.new do |spec| 10 | spec.name = "audit-log" 11 | spec.version = AuditLog::VERSION 12 | spec.authors = ["Jason Lee"] 13 | spec.email = ["huacnlee@gmail.com"] 14 | spec.homepage = "https://github.com/rails-engine/audit-log" 15 | spec.summary = "Trail audit logs (Operation logs) into the database for user behaviors, including a web UI to query logs" 16 | spec.description = "Trail audit logs (Operation logs) into the database for user behaviors, including a web UI to query logs." 17 | spec.license = "MIT" 18 | 19 | spec.files = Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"] 20 | 21 | spec.add_dependency "kaminari", ">= 0.15" 22 | spec.add_dependency "rails", ">= 5.2" 23 | end 24 | -------------------------------------------------------------------------------- /bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # This command will automatically be run when you run "rails" with Rails gems 5 | # installed from the root of your application. 6 | 7 | ENGINE_ROOT = File.expand_path("..", __dir__) 8 | ENGINE_PATH = File.expand_path("../lib/audit-log/engine", __dir__) 9 | 10 | # Set up gems listed in the Gemfile. 11 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) 12 | require "bundler/setup" if File.exist?(ENV["BUNDLE_GEMFILE"]) 13 | 14 | require "rails/all" 15 | require "rails/engine/commands" 16 | -------------------------------------------------------------------------------- /bin/test: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH << File.expand_path("../test", __dir__) 5 | 6 | require "bundler/setup" 7 | require "rails/plugin/test" 8 | -------------------------------------------------------------------------------- /config/initializers/audit-log.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | AuditLog.configure do 4 | # class name of you User model, default: 'User' 5 | # self.user_class = "User" 6 | # current_user method name in your Controller, default: 'current_user' 7 | # self.current_user_method = "current_user" 8 | # Speical a table_name for AuditLog model, default: "audit_logs" 9 | # self.table_name = "audit_logs" 10 | end 11 | -------------------------------------------------------------------------------- /config/locales/audit-log.yml: -------------------------------------------------------------------------------- 1 | en: 2 | audit_log: 3 | action: 4 | list_audit_log: List Audit Log 5 | create_audit_log: Create Audit Log 6 | update_audit_log: Update Audit Log 7 | update_password: Update Password -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | AuditLog::Engine.routes.draw do 4 | resources :logs, path: "" 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20190527035005_create_audit_logs.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateAuditLogs < ActiveRecord::Migration[5.2] 4 | def change 5 | create_table "audit_logs", force: :cascade do |t| 6 | t.string "action", null: false 7 | t.bigint "user_id" 8 | t.bigint "record_id" 9 | t.string "record_type" 10 | t.text "payload" 11 | t.text "request" 12 | t.datetime "created_at" 13 | t.datetime "updated_at" 14 | t.index %w[record_type record_id], using: :btree 15 | t.index %w[user_id action], using: :btree 16 | t.index ["action"], using: :btree 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /gemfiles/Gemfile-5-2: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gemspec path: '..' 4 | 5 | gem 'rails', '~> 5.2.0' 6 | eval File.read(File.expand_path('../../Gemfile-dev', __FILE__)), nil, "Gemfile-dev" 7 | -------------------------------------------------------------------------------- /gemfiles/Gemfile-6-0: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gemspec path: '..' 4 | 5 | gem 'rails', '~> 6.0.0' 6 | eval File.read(File.expand_path('../../Gemfile-dev', __FILE__)), nil, "Gemfile-dev" 7 | -------------------------------------------------------------------------------- /lib/audit-log.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative "./audit-log/version" 4 | require_relative "./audit-log/configuration" 5 | require_relative "./audit-log/model" 6 | require_relative "./audit-log/log_subscriber" 7 | require_relative "./audit-log/engine" 8 | require "kaminari" 9 | 10 | module AuditLog 11 | class << self 12 | def config 13 | return @config if defined?(@config) 14 | 15 | @config = Configuration.new 16 | @config.user_class = "User" 17 | @config.current_user_method = "current_user" 18 | @config.user_name_method = "name" 19 | @config.table_name = "audit_logs" 20 | @config 21 | end 22 | 23 | def configure(&block) 24 | config.instance_exec(&block) 25 | end 26 | 27 | # Create an audit log 28 | # 29 | # AuditLog.audit!(:edit_account, @account, payload: account_params, user: current_user) 30 | def audit!(action, record = nil, payload: nil, user: nil, request: nil) 31 | ActiveSupport::Notifications.instrument("audit.audit_log", action: action) do 32 | request_info = {} 33 | if request 34 | request_info = { 35 | request_id: request.request_id, 36 | ip: request.remote_ip, 37 | url: request.url, 38 | user_agent: request.user_agent 39 | } 40 | end 41 | 42 | # Set nil if record is a new_record, do this for avoid create record. 43 | record = nil if record&.new_record? 44 | 45 | Rails.logger.silence do 46 | AuditLog::Log.create!( 47 | action: action, 48 | record: record, 49 | payload: (payload || {}).to_h.deep_stringify_keys, 50 | user: user, 51 | request: request_info.deep_stringify_keys 52 | ) 53 | end 54 | end 55 | end 56 | 57 | # Get I18n action name options for select 58 | def action_options 59 | I18n.t("audit_log.action").map { |k, v| [v, k.to_s] } 60 | end 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /lib/audit-log/configuration.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module AuditLog 4 | class Configuration 5 | # class name of you User model, default: 'User' 6 | attr_accessor :user_class 7 | 8 | # current_user method name in your Controller, default: 'current_user' 9 | attr_accessor :current_user_method 10 | 11 | # user name method, default: "name" 12 | attr_accessor :user_name_method 13 | 14 | # set a speicla table_name for AuditLog Model, default: 'audit_logs' 15 | attr_accessor :table_name 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /lib/audit-log/controller_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module AuditLog 4 | module ControllerHelper 5 | # Create an audit log 6 | # 7 | # audit!(:edit_account, @account, payload: account_params) 8 | def audit!(action, record = nil, payload: nil, user: nil) 9 | user ||= send(AuditLog.config.current_user_method.to_sym) 10 | AuditLog.audit!(action, record, payload: payload, request: request, user: user) 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/audit-log/engine.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative "./controller_helper" 4 | 5 | module AuditLog 6 | class Engine < Rails::Engine 7 | isolate_namespace AuditLog 8 | 9 | ActiveSupport.on_load(:action_controller) do 10 | prepend AuditLog::ControllerHelper 11 | end 12 | 13 | AuditLog::LogSubscriber.attach_to :audit_log 14 | 15 | initializer "audit-log.assets.precompile", group: :all do |app| 16 | app.config.assets.precompile += %w[audit-log/application.css] 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /lib/audit-log/log_subscriber.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module AuditLog 4 | class LogSubscriber < ActiveSupport::LogSubscriber 5 | # ActiveSupport::Notifications.instrument('audit.audit_log', action: action) 6 | def audit(event) 7 | prefix = color("AuditLog", CYAN) 8 | action = color(event.payload[:action], BLUE) 9 | debug " #{prefix} #{action} (#{event.duration.round(1)}ms)" 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /lib/audit-log/model.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module AuditLog 4 | module Model 5 | extend ActiveSupport::Concern 6 | 7 | included do 8 | self.table_name = AuditLog.config.table_name 9 | 10 | serialize :payload, JSON 11 | serialize :request, JSON 12 | 13 | belongs_to :user, class_name: AuditLog.config.user_class, required: false 14 | belongs_to :record, polymorphic: true, required: false 15 | 16 | validates :action, presence: true 17 | 18 | after_initialize :initialize_payload_request 19 | end 20 | 21 | def initialize_payload_request 22 | self.payload = {} if payload.nil? 23 | self.request = {} if request.nil? 24 | end 25 | 26 | def user_name 27 | return "none" if user.blank? 28 | 29 | user.send(AuditLog.config.user_name_method) 30 | end 31 | 32 | def action_name 33 | I18n.t("audit_log.action.#{action}", default: action) 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /lib/audit-log/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module AuditLog 4 | VERSION = "1.2.0" 5 | end 6 | -------------------------------------------------------------------------------- /lib/generators/audit_log/install_generator.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "rails/generators" 4 | module AuditLog 5 | module Generators 6 | class InstallGenerator < Rails::Generators::Base 7 | desc "Create AuditLog's base files" 8 | source_root File.expand_path("../../..", __dir__) 9 | 10 | def add_initializer 11 | template "config/initializers/audit-log.rb", "config/initializers/audit-log.rb" 12 | template "config/locales/audit-log.yml", "config/locales/audit-log.yml" 13 | end 14 | 15 | def add_migrations 16 | exec("rake audit_log:install:migrations") 17 | end 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /test/controllers/navigation_test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "test_helper" 4 | 5 | class NavigationTest < ActionDispatch::IntegrationTest 6 | setup do 7 | @current_user = create(:user) 8 | end 9 | 10 | test "GET /audit-log" do 11 | get "/" 12 | assert_equal 200, response.status 13 | 14 | sign_in @current_user 15 | get "/comments/new" 16 | assert_equal 200, response.status 17 | 18 | comment = create(:comment) 19 | get "/comments/#{comment.id}" 20 | assert_equal 200, response.status 21 | 22 | assert AuditLog::Log.count > 2 23 | 24 | logs_count = AuditLog::Log.count 25 | 26 | get "/audit-log" 27 | assert_equal 200, response.status 28 | assert_select "tbody tr", count: logs_count 29 | 30 | get "/audit-log?q=comment" 31 | assert_select "tbody tr", count: 2 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /test/dummy/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files for more about ignoring files. 2 | # 3 | # If you find yourself ignoring temporary files generated by your text editor 4 | # or operating system, you probably want to add a global ignore instead: 5 | # git config --global core.excludesfile '~/.gitignore_global' 6 | 7 | # Ignore bundler config. 8 | /.bundle 9 | 10 | # Ignore all logfiles and tempfiles. 11 | /log/* 12 | !/log/.keep 13 | /tmp 14 | -------------------------------------------------------------------------------- /test/dummy/Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | gem "devise" 4 | -------------------------------------------------------------------------------- /test/dummy/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | specs: 3 | actionpack (5.2.3) 4 | actionview (= 5.2.3) 5 | activesupport (= 5.2.3) 6 | rack (~> 2.0) 7 | rack-test (>= 0.6.3) 8 | rails-dom-testing (~> 2.0) 9 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 10 | actionview (5.2.3) 11 | activesupport (= 5.2.3) 12 | builder (~> 3.1) 13 | erubi (~> 1.4) 14 | rails-dom-testing (~> 2.0) 15 | rails-html-sanitizer (~> 1.0, >= 1.0.3) 16 | activesupport (5.2.3) 17 | concurrent-ruby (~> 1.0, >= 1.0.2) 18 | i18n (>= 0.7, < 2) 19 | minitest (~> 5.1) 20 | tzinfo (~> 1.1) 21 | bcrypt (3.1.12) 22 | builder (3.2.3) 23 | concurrent-ruby (1.1.5) 24 | crass (1.0.4) 25 | devise (4.6.2) 26 | bcrypt (~> 3.0) 27 | orm_adapter (~> 0.1) 28 | railties (>= 4.1.0, < 6.0) 29 | responders 30 | warden (~> 1.2.3) 31 | erubi (1.8.0) 32 | i18n (1.6.0) 33 | concurrent-ruby (~> 1.0) 34 | loofah (2.2.3) 35 | crass (~> 1.0.2) 36 | nokogiri (>= 1.5.9) 37 | method_source (0.9.2) 38 | mini_portile2 (2.4.0) 39 | minitest (5.11.3) 40 | nokogiri (1.10.3) 41 | mini_portile2 (~> 2.4.0) 42 | orm_adapter (0.5.0) 43 | rack (2.0.7) 44 | rack-test (1.1.0) 45 | rack (>= 1.0, < 3) 46 | rails-dom-testing (2.0.3) 47 | activesupport (>= 4.2.0) 48 | nokogiri (>= 1.6) 49 | rails-html-sanitizer (1.0.4) 50 | loofah (~> 2.2, >= 2.2.2) 51 | railties (5.2.3) 52 | actionpack (= 5.2.3) 53 | activesupport (= 5.2.3) 54 | method_source 55 | rake (>= 0.8.7) 56 | thor (>= 0.19.0, < 2.0) 57 | rake (12.3.2) 58 | responders (2.4.1) 59 | actionpack (>= 4.2.0, < 6.0) 60 | railties (>= 4.2.0, < 6.0) 61 | thor (0.20.3) 62 | thread_safe (0.3.6) 63 | tzinfo (1.2.5) 64 | thread_safe (~> 0.1) 65 | warden (1.2.8) 66 | rack (>= 2.0.6) 67 | 68 | PLATFORMS 69 | ruby 70 | 71 | DEPENDENCIES 72 | devise 73 | 74 | BUNDLED WITH 75 | 2.0.1 76 | -------------------------------------------------------------------------------- /test/dummy/Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Add your own tasks in files placed in lib/tasks ending in .rake, 4 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 5 | 6 | require File.expand_path("config/application", __dir__) 7 | 8 | Rails.application.load_tasks 9 | -------------------------------------------------------------------------------- /test/dummy/app/assets/config/manifest.js: -------------------------------------------------------------------------------- 1 | //= link application.css 2 | //= link application.js 3 | -------------------------------------------------------------------------------- /test/dummy/app/assets/images/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rails-engine/audit-log/7fac678f007d9a7337a990f5ca7eb3d37351b477/test/dummy/app/assets/images/.keep -------------------------------------------------------------------------------- /test/dummy/app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into application.js, which will include all the files 2 | // listed below. 3 | // 4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, 5 | // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path. 6 | // 7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 8 | // compiled file. 9 | // 10 | // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details 11 | // about supported directives. 12 | // 13 | //= require jquery 14 | //= require jquery_ujs 15 | //= require_tree . 16 | -------------------------------------------------------------------------------- /test/dummy/app/assets/stylesheets/application.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.css, which will include all the files 3 | * listed below. 4 | * 5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, 6 | * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path. 7 | * 8 | * You're free to add application-wide styles to this file and they'll appear at the bottom of the 9 | * compiled file so the styles you add here take precedence over styles defined in any styles 10 | * defined in the other CSS/SCSS files in this directory. It is generally better to create a new 11 | * file per style scope. 12 | * 13 | *= require_self 14 | *= require notifications 15 | */ 16 | 17 | @import "bootstrap"; 18 | 19 | 20 | body { 21 | font-size: 14px; 22 | } 23 | -------------------------------------------------------------------------------- /test/dummy/app/assets/stylesheets/notifications.scss: -------------------------------------------------------------------------------- 1 | .notifications { 2 | padding: 10px; 3 | margin: 20px; 4 | border: 1px solid #eee; 5 | border-radius: 3px; 6 | 7 | .heading { 8 | border-bottom: 1px solid #eee; 9 | padding: 5px; 10 | margin-bottom: 10px; 11 | } 12 | 13 | 14 | .notification-group { 15 | padding: 10px; 16 | margin-bottom: 20px; 17 | 18 | .group-title { 19 | padding: 5px 0; 20 | color: #999; 21 | border-bottom: 1px solid #eee; 22 | } 23 | } 24 | 25 | .notification { 26 | margin: 0; 27 | padding: 10px 0px; 28 | color: #999; 29 | 30 | a { color: #555; } 31 | 32 | &.unread { 33 | color: #444; 34 | 35 | .media-heading { 36 | font-weight: bold; 37 | font-size: 14px; 38 | } 39 | 40 | a { color: #222; text-decoration: underline; } 41 | } 42 | 43 | 44 | .media-content { 45 | p:last-child { 46 | margin-bottom: 0; 47 | } 48 | } 49 | 50 | .user-avatar { 51 | img { width: 32px; height: 32px; border-radius: 120px; } 52 | } 53 | 54 | .media-right { 55 | min-width: 100px; 56 | color: #AAA; 57 | font-size: 13px; 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /test/dummy/app/assets/stylesheets/scaffolds.scss: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #fff; 3 | color: #333; 4 | font-family: verdana, arial, helvetica, sans-serif; 5 | font-size: 13px; 6 | line-height: 18px; 7 | margin: 33px; 8 | } 9 | 10 | p, ol, ul, td { 11 | font-family: verdana, arial, helvetica, sans-serif; 12 | font-size: 13px; 13 | line-height: 18px; 14 | margin: 33px; 15 | } 16 | 17 | pre { 18 | background-color: #eee; 19 | padding: 10px; 20 | font-size: 11px; 21 | } 22 | 23 | a { 24 | color: #000; 25 | 26 | &:visited { 27 | color: #666; 28 | } 29 | 30 | &:hover { 31 | color: #fff; 32 | background-color: #000; 33 | } 34 | } 35 | 36 | th { 37 | padding-bottom: 5px; 38 | } 39 | 40 | td { 41 | padding-bottom: 7px; 42 | padding-left: 5px; 43 | padding-right: 5px; 44 | } 45 | 46 | div { 47 | &.field, &.actions { 48 | margin-bottom: 10px; 49 | } 50 | } 51 | 52 | #notice { 53 | color: green; 54 | } 55 | 56 | .field_with_errors { 57 | padding: 2px; 58 | background-color: red; 59 | display: table; 60 | } 61 | 62 | #error_explanation { 63 | width: 450px; 64 | border: 2px solid red; 65 | padding: 7px; 66 | padding-bottom: 0; 67 | margin-bottom: 20px; 68 | background-color: #f0f0f0; 69 | 70 | h2 { 71 | text-align: left; 72 | font-weight: bold; 73 | padding: 5px 5px 5px 15px; 74 | font-size: 12px; 75 | margin: -7px; 76 | margin-bottom: 0; 77 | background-color: #c00; 78 | color: #fff; 79 | } 80 | 81 | ul li { 82 | font-size: 12px; 83 | list-style: square; 84 | } 85 | } 86 | 87 | label { 88 | display: block; 89 | } 90 | -------------------------------------------------------------------------------- /test/dummy/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ApplicationController < ActionController::Base 4 | # Prevent CSRF attacks by raising an exception. 5 | # For APIs, you may want to use :null_session instead. 6 | protect_from_forgery with: :exception 7 | 8 | def custom_current_user 9 | current_user 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /test/dummy/app/controllers/comments_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CommentsController < ApplicationController 4 | before_action :authenticate_user! 5 | before_action :set_comment, only: %i[show edit update destroy] 6 | 7 | # GET /comments 8 | def index 9 | @comments = Comment.all 10 | audit! :list_comment 11 | end 12 | 13 | # GET /comments/1 14 | def show 15 | audit! :show_comment, @comment 16 | end 17 | 18 | # GET /comments/new 19 | def new 20 | audit! :new_comment 21 | @comment = Comment.new 22 | end 23 | 24 | # GET /comments/1/edit 25 | def edit 26 | audit! :edit_comment, @comment 27 | end 28 | 29 | # POST /comments 30 | def create 31 | @comment = Comment.new(comment_params) 32 | @comment.user = current_user 33 | 34 | if @comment.save 35 | audit! :create_comment, @comment, payload: comment_params 36 | redirect_to @comment, notice: "Comment was successfully created." 37 | else 38 | render :new 39 | end 40 | end 41 | 42 | # PATCH/PUT /comments/1 43 | def update 44 | if @comment.update(comment_params) 45 | audit! :update_comment, @comment, payload: comment_params 46 | redirect_to @comment, notice: "Comment was successfully updated." 47 | else 48 | render :edit 49 | end 50 | end 51 | 52 | # DELETE /comments/1 53 | def destroy 54 | @comment.destroy 55 | audit! :delete_comment, @comment, payload: @comment.attributes 56 | redirect_to comments_url, notice: "Comment was successfully destroyed." 57 | end 58 | 59 | private 60 | 61 | # Use callbacks to share common setup or constraints between actions. 62 | def set_comment 63 | @comment = Comment.find(params[:id]) 64 | end 65 | 66 | # Only allow a trusted parameter "white list" through. 67 | def comment_params 68 | params.require(:comment).permit(:topic_id, :user_id, :body) 69 | end 70 | end 71 | -------------------------------------------------------------------------------- /test/dummy/app/controllers/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rails-engine/audit-log/7fac678f007d9a7337a990f5ca7eb3d37351b477/test/dummy/app/controllers/concerns/.keep -------------------------------------------------------------------------------- /test/dummy/app/controllers/topics_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class TopicsController < ApplicationController 4 | before_action :authenticate_user! 5 | before_action :set_topic, only: %i[show edit update destroy] 6 | 7 | # GET /topics 8 | def index 9 | @topics = Topic.all 10 | audit! :list_topic 11 | end 12 | 13 | # GET /topics/1 14 | def show; end 15 | 16 | # GET /topics/new 17 | def new 18 | @topic = Topic.new 19 | audit! :new_topic 20 | end 21 | 22 | # GET /topics/1/edit 23 | def edit; end 24 | 25 | # POST /topics 26 | def create 27 | @topic = Topic.new(topic_params) 28 | @topic.user = current_user 29 | 30 | if @topic.save 31 | redirect_to @topic, notice: "Topic was successfully created." 32 | else 33 | render :new 34 | end 35 | end 36 | 37 | # PATCH/PUT /topics/1 38 | def update 39 | if @topic.update(topic_params) 40 | redirect_to @topic, notice: "Topic was successfully updated." 41 | else 42 | render :edit 43 | end 44 | end 45 | 46 | # DELETE /topics/1 47 | def destroy 48 | @topic.destroy 49 | redirect_to topics_url, notice: "Topic was successfully destroyed." 50 | end 51 | 52 | private 53 | 54 | # Use callbacks to share common setup or constraints between actions. 55 | def set_topic 56 | @topic = Topic.find(params[:id]) 57 | end 58 | 59 | # Only allow a trusted parameter "white list" through. 60 | def topic_params 61 | params.require(:topic).permit(:title, :user_id) 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /test/dummy/app/controllers/welcome_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class WelcomeController < ApplicationController 4 | def index 5 | audit! :home 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /test/dummy/app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module ApplicationHelper 4 | end 5 | -------------------------------------------------------------------------------- /test/dummy/app/helpers/comments_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module CommentsHelper 4 | end 5 | -------------------------------------------------------------------------------- /test/dummy/app/helpers/topics_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module TopicsHelper 4 | end 5 | -------------------------------------------------------------------------------- /test/dummy/app/mailers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rails-engine/audit-log/7fac678f007d9a7337a990f5ca7eb3d37351b477/test/dummy/app/mailers/.keep -------------------------------------------------------------------------------- /test/dummy/app/models/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rails-engine/audit-log/7fac678f007d9a7337a990f5ca7eb3d37351b477/test/dummy/app/models/.keep -------------------------------------------------------------------------------- /test/dummy/app/models/application_record.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ApplicationRecord < ActiveRecord::Base 4 | self.abstract_class = true 5 | end 6 | -------------------------------------------------------------------------------- /test/dummy/app/models/comment.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class Comment < ApplicationRecord 4 | belongs_to :user 5 | belongs_to :topic 6 | end 7 | -------------------------------------------------------------------------------- /test/dummy/app/models/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rails-engine/audit-log/7fac678f007d9a7337a990f5ca7eb3d37351b477/test/dummy/app/models/concerns/.keep -------------------------------------------------------------------------------- /test/dummy/app/models/topic.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class Topic < ActiveRecord::Base 4 | belongs_to :user 5 | end 6 | -------------------------------------------------------------------------------- /test/dummy/app/models/user.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class User < ActiveRecord::Base 4 | # Include default devise modules. Others available are: 5 | # :confirmable, :lockable, :timeoutable and :omniauthable 6 | devise :database_authenticatable, :registerable, 7 | :recoverable, :rememberable, :trackable 8 | 9 | def name 10 | email.split("@").first 11 | end 12 | 13 | def profile_url 14 | "/users/#{id}" 15 | end 16 | 17 | def avatar_url 18 | "//www.gravatar.com/avatar/#{Digest::MD5.hexdigest(email)}" 19 | end 20 | 21 | def admin? 22 | email == "huacnlee@gmail.com" 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /test/dummy/app/views/comments/_form.html.erb: -------------------------------------------------------------------------------- 1 | <%= form_for(comment) do |f| %> 2 | <% if comment.errors.any? %> 3 |
4 |

<%= pluralize(comment.errors.count, "error") %> prohibited this comment from being saved:

5 | 6 |
    7 | <% comment.errors.full_messages.each do |message| %> 8 |
  • <%= message %>
  • 9 | <% end %> 10 |
11 |
12 | <% end %> 13 | 14 |
15 | <%= f.label :topic_id, class: 'control-label' %> 16 | <%= f.select :topic_id, Topic.all.collect{|t| [t.title, t.id]}, {}, { class: 'form-control' } %> 17 |
18 | 19 |
20 | <%= f.label :body, class: 'control-label' %> 21 | <%= f.text_area :body, class: 'form-control' %> 22 |
23 | 24 |
25 | <%= f.submit class: 'btn btn-primary' %> 26 |
27 | <% end %> 28 | -------------------------------------------------------------------------------- /test/dummy/app/views/comments/edit.html.erb: -------------------------------------------------------------------------------- 1 |

Editing Comment

2 | 3 | <%= render 'form', comment: @comment %> 4 | -------------------------------------------------------------------------------- /test/dummy/app/views/comments/index.html.erb: -------------------------------------------------------------------------------- 1 |

<%= notice %>

2 | 3 |

Comments

4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | <% @comments.each do |comment| %> 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | <% end %> 26 | 27 |
TopicUserBody
<%= comment.topic_id %><%= comment.user_id %><%= comment.body %><%= link_to 'Show', comment %><%= link_to 'Edit', edit_comment_path(comment) %><%= link_to 'Destroy', comment, method: :delete, data: { confirm: 'Are you sure?' } %>
28 | 29 |
30 | 31 | <%= link_to 'New Comment', new_comment_path %> 32 | -------------------------------------------------------------------------------- /test/dummy/app/views/comments/new.html.erb: -------------------------------------------------------------------------------- 1 |

New Comment

2 | 3 | <%= render 'form', comment: @comment %> 4 | -------------------------------------------------------------------------------- /test/dummy/app/views/comments/show.html.erb: -------------------------------------------------------------------------------- 1 |

<%= notice %>

2 | 3 |

4 | Topic: 5 | <%= @comment.topic_id %> 6 |

7 | 8 |

9 | User: 10 | <%= @comment.user_id %> 11 |

12 | 13 |

14 | Body: 15 | <%= @comment.body %> 16 |

17 | 18 | <%= link_to 'Edit', edit_comment_path(@comment) %> | 19 | <%= link_to 'Back', comments_path %> 20 | -------------------------------------------------------------------------------- /test/dummy/app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Dummy 5 | <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %> 6 | <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %> 7 | <%= csrf_meta_tags %> 8 | 9 | 10 | 11 | 32 | 33 |
34 | <%= yield %> 35 |
36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /test/dummy/app/views/notifications/_comment.html.erb: -------------------------------------------------------------------------------- 1 | <% if notification.second_target && notification.target %> 2 |
3 | Comment on <%= link_to notification&.second_target&.title, main_app.topic_path(notification.second_target) %>: 4 |
5 |
6 | <%= simple_format notification&.target&.body %> 7 |
8 | <% end %> 9 | -------------------------------------------------------------------------------- /test/dummy/app/views/notifications/_new_topic.html.erb: -------------------------------------------------------------------------------- 1 | <% if notification.target %> 2 |
3 | Created topic <%= link_to notification&.target&.title, main_app.topic_path(notification.target) %> 4 |
5 | <% end %> 6 | -------------------------------------------------------------------------------- /test/dummy/app/views/topics/_form.html.erb: -------------------------------------------------------------------------------- 1 | <%= form_for(topic) do |f| %> 2 | <% if topic.errors.any? %> 3 |
4 |

<%= pluralize(topic.errors.count, "error") %> prohibited this topic from being saved:

5 | 6 | 11 |
12 | <% end %> 13 | 14 |
15 | <%= f.label :title %> 16 | <%= f.text_field :title %> 17 |
18 | 19 |
20 | <%= f.submit %> 21 |
22 | <% end %> 23 | -------------------------------------------------------------------------------- /test/dummy/app/views/topics/edit.html.erb: -------------------------------------------------------------------------------- 1 |

Editing Topic

2 | 3 | <%= render 'form', topic: @topic %> 4 | 5 | <%= link_to 'Show', @topic %> | 6 | <%= link_to 'Back', topics_path %> 7 | -------------------------------------------------------------------------------- /test/dummy/app/views/topics/index.html.erb: -------------------------------------------------------------------------------- 1 |

<%= notice %>

2 | 3 |

Topics

4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | <% @topics.each do |topic| %> 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | <% end %> 24 | 25 |
TitleUser
<%= topic.title %><%= topic.user_id %><%= link_to 'Show', topic %><%= link_to 'Edit', edit_topic_path(topic) %><%= link_to 'Destroy', topic, method: :delete, data: { confirm: 'Are you sure?' } %>
26 | 27 |
28 | 29 | <%= link_to 'New Topic', new_topic_path %> 30 | -------------------------------------------------------------------------------- /test/dummy/app/views/topics/new.html.erb: -------------------------------------------------------------------------------- 1 |

New Topic

2 | 3 | <%= render 'form', topic: @topic %> 4 | 5 | <%= link_to 'Back', topics_path %> 6 | -------------------------------------------------------------------------------- /test/dummy/app/views/topics/show.html.erb: -------------------------------------------------------------------------------- 1 |

<%= notice %>

2 | 3 |

4 | Title: 5 | <%= @topic.title %> 6 |

7 | 8 |

9 | User: 10 | <%= @topic.user_id %> 11 |

12 | 13 | <%= link_to 'Edit', edit_topic_path(@topic) %> | 14 | <%= link_to 'Back', topics_path %> 15 | -------------------------------------------------------------------------------- /test/dummy/app/views/welcome/index.html.erb: -------------------------------------------------------------------------------- 1 |
2 |

Welcome to Dummy App.

3 | 4 |
    5 |
  1. 6 | Create A Topic 7 |
  2. 8 |
  3. 9 | Create a little Comment 10 |
  4. 11 |
  5. 12 | AuditLogs 13 |
  6. 14 |
15 | 16 |
17 | -------------------------------------------------------------------------------- /test/dummy/bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) 5 | load Gem.bin_path("bundler", "bundle") 6 | -------------------------------------------------------------------------------- /test/dummy/bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | APP_PATH = File.expand_path("../config/application", __dir__) 5 | require_relative "../config/boot" 6 | require "rails/commands" 7 | -------------------------------------------------------------------------------- /test/dummy/bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | require_relative "../config/boot" 5 | require "rake" 6 | Rake.application.run 7 | -------------------------------------------------------------------------------- /test/dummy/bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | require "pathname" 5 | require "fileutils" 6 | include FileUtils 7 | 8 | # path to your application root. 9 | APP_ROOT = Pathname.new File.expand_path("..", __dir__) 10 | 11 | def system!(*args) 12 | system(*args) || abort("\n== Command #{args} failed ==") 13 | end 14 | 15 | chdir APP_ROOT do 16 | # This script is a starting point to setup your application. 17 | # Add necessary setup steps to this file. 18 | 19 | puts "== Installing dependencies ==" 20 | system! "gem install bundler --conservative" 21 | system("bundle check") || system!("bundle install") 22 | 23 | # puts "\n== Copying sample files ==" 24 | # unless File.exist?('config/database.yml') 25 | # cp 'config/database.yml.sample', 'config/database.yml' 26 | # end 27 | 28 | puts "\n== Preparing database ==" 29 | system! "bin/rails db:setup" 30 | 31 | puts "\n== Removing old logs and tempfiles ==" 32 | system! "bin/rails log:clear tmp:clear" 33 | 34 | puts "\n== Restarting application server ==" 35 | system! "bin/rails restart" 36 | end 37 | -------------------------------------------------------------------------------- /test/dummy/bin/update: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | require "pathname" 5 | require "fileutils" 6 | include FileUtils 7 | 8 | # path to your application root. 9 | APP_ROOT = Pathname.new File.expand_path("..", __dir__) 10 | 11 | def system!(*args) 12 | system(*args) || abort("\n== Command #{args} failed ==") 13 | end 14 | 15 | chdir APP_ROOT do 16 | # This script is a way to update your development environment automatically. 17 | # Add necessary update steps to this file. 18 | 19 | puts "== Installing dependencies ==" 20 | system! "gem install bundler --conservative" 21 | system("bundle check") || system!("bundle install") 22 | 23 | puts "\n== Updating database ==" 24 | system! "bin/rails db:migrate" 25 | 26 | puts "\n== Removing old logs and tempfiles ==" 27 | system! "bin/rails log:clear tmp:clear" 28 | 29 | puts "\n== Restarting application server ==" 30 | system! "bin/rails restart" 31 | end 32 | -------------------------------------------------------------------------------- /test/dummy/config.ru: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # This file is used by Rack-based servers to start the application. 4 | 5 | require ::File.expand_path("config/environment", __dir__) 6 | run Rails.application 7 | -------------------------------------------------------------------------------- /test/dummy/config/application.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative "boot" 4 | 5 | require "rails/all" 6 | 7 | # Require the gems listed in Gemfile, including any gems 8 | # you've limited to :test, :development, or :production. 9 | Bundler.require(*Rails.groups) 10 | 11 | module Dummy 12 | class Application < Rails::Application 13 | # Settings in config/environments/* take precedence over those specified here. 14 | # Application configuration should go into files in config/initializers 15 | # -- all .rb files in that directory are automatically loaded. 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /test/dummy/config/boot.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) 4 | 5 | require "bundler/setup" # Set up gems listed in the Gemfile. 6 | -------------------------------------------------------------------------------- /test/dummy/config/cable.yml: -------------------------------------------------------------------------------- 1 | development: 2 | adapter: async 3 | 4 | test: 5 | adapter: async 6 | 7 | production: 8 | adapter: redis 9 | url: redis://localhost:6379/1 10 | -------------------------------------------------------------------------------- /test/dummy/config/database.yml: -------------------------------------------------------------------------------- 1 | default: &default 2 | adapter: postgresql 3 | timeout: 5000 4 | encoding: utf-8 5 | 6 | development: 7 | <<: *default 8 | database: audit_log_dummy_development 9 | 10 | test: 11 | <<: *default 12 | database: audit_log_dummy_test 13 | 14 | production: 15 | <<: *default 16 | url: <%= ENV['DATABASE_URL'] %> 17 | -------------------------------------------------------------------------------- /test/dummy/config/environment.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Load the Rails application. 4 | require_relative "application" 5 | 6 | # Initialize the Rails application. 7 | Rails.application.initialize! 8 | -------------------------------------------------------------------------------- /test/dummy/config/environments/development.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Rails.application.configure do 4 | # Settings specified here will take precedence over those in config/application.rb. 5 | 6 | # In the development environment your application's code is reloaded on 7 | # every request. This slows down response time but is perfect for development 8 | # since you don't have to restart the web server when you make code changes. 9 | config.cache_classes = false 10 | 11 | # Do not eager load code on boot. 12 | config.eager_load = false 13 | 14 | # Show full error reports. 15 | config.consider_all_requests_local = true 16 | 17 | # Enable/disable caching. By default caching is disabled. 18 | if Rails.root.join("tmp/caching-dev.txt").exist? 19 | config.action_controller.perform_caching = true 20 | 21 | config.cache_store = :memory_store 22 | # config.public_file_server.headers = { 23 | # 'Cache-Control' => 'public, max-age=172800' 24 | # } 25 | else 26 | config.action_controller.perform_caching = false 27 | 28 | config.cache_store = :null_store 29 | end 30 | 31 | # Don't care if the mailer can't send. 32 | config.action_mailer.raise_delivery_errors = false 33 | 34 | # Print deprecation notices to the Rails logger. 35 | config.active_support.deprecation = :log 36 | 37 | # Raise an error on page load if there are pending migrations. 38 | config.active_record.migration_error = :page_load 39 | 40 | # Debug mode disables concatenation and preprocessing of assets. 41 | # This option may cause significant delays in view rendering with a large 42 | # number of complex assets. 43 | config.assets.debug = true 44 | 45 | # Suppress logger output for asset requests. 46 | config.assets.quiet = true 47 | 48 | # Raises error for missing translations 49 | # config.action_view.raise_on_missing_translations = true 50 | 51 | # Use an evented file watcher to asynchronously detect changes in source code, 52 | # routes, locales, etc. This feature depends on the listen gem. 53 | # config.file_watcher = ActiveSupport::EventedFileUpdateChecker 54 | end 55 | -------------------------------------------------------------------------------- /test/dummy/config/environments/production.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Rails.application.configure do 4 | # Settings specified here will take precedence over those in config/application.rb. 5 | 6 | # Code is not reloaded between requests. 7 | config.cache_classes = true 8 | 9 | # Eager load code on boot. This eager loads most of Rails and 10 | # your application in memory, allowing both threaded web servers 11 | # and those relying on copy on write to perform better. 12 | # Rake tasks automatically ignore this option for performance. 13 | config.eager_load = true 14 | 15 | # Full error reports are disabled and caching is turned on. 16 | config.consider_all_requests_local = false 17 | config.action_controller.perform_caching = true 18 | 19 | # Disable serving static files from the `/public` folder by default since 20 | # Apache or NGINX already handles this. 21 | # config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? 22 | 23 | # Compress JavaScripts and CSS. 24 | config.assets.js_compressor = :uglifier 25 | # config.assets.css_compressor = :sass 26 | 27 | # Do not fallback to assets pipeline if a precompiled asset is missed. 28 | config.assets.compile = false 29 | 30 | # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb 31 | 32 | # Enable serving of images, stylesheets, and JavaScripts from an asset server. 33 | # config.action_controller.asset_host = 'http://assets.example.com' 34 | 35 | # Specifies the header that your server uses for sending files. 36 | # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache 37 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX 38 | 39 | # Mount Action Cable outside main process or domain 40 | # config.action_cable.mount_path = nil 41 | # config.action_cable.url = 'wss://example.com/cable' 42 | # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ] 43 | 44 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 45 | # config.force_ssl = true 46 | 47 | # Use the lowest log level to ensure availability of diagnostic information 48 | # when problems arise. 49 | config.log_level = :debug 50 | 51 | # Prepend all log lines with the following tags. 52 | config.log_tags = [:request_id] 53 | 54 | # Use a different cache store in production. 55 | # config.cache_store = :mem_cache_store 56 | 57 | # Use a real queuing backend for Active Job (and separate queues per environment) 58 | # config.active_job.queue_adapter = :resque 59 | # config.active_job.queue_name_prefix = "dummy_#{Rails.env}" 60 | 61 | # Ignore bad email addresses and do not raise email delivery errors. 62 | # Set this to true and configure the email server for immediate delivery to raise delivery errors. 63 | # config.action_mailer.raise_delivery_errors = false 64 | 65 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 66 | # the I18n.default_locale when a translation cannot be found). 67 | config.i18n.fallbacks = true 68 | 69 | # Send deprecation notices to registered listeners. 70 | config.active_support.deprecation = :notify 71 | 72 | # Use default logging formatter so that PID and timestamp are not suppressed. 73 | config.log_formatter = ::Logger::Formatter.new 74 | 75 | # Use a different logger for distributed setups. 76 | # require 'syslog/logger' 77 | # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name') 78 | 79 | if ENV["RAILS_LOG_TO_STDOUT"].present? 80 | logger = ActiveSupport::Logger.new($stdout) 81 | logger.formatter = config.log_formatter 82 | config.logger = ActiveSupport::TaggedLogging.new(logger) 83 | end 84 | 85 | # Do not dump schema after migrations. 86 | config.active_record.dump_schema_after_migration = false 87 | end 88 | -------------------------------------------------------------------------------- /test/dummy/config/environments/test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Rails.application.configure do 4 | # Settings specified here will take precedence over those in config/application.rb. 5 | 6 | # The test environment is used exclusively to run your application's 7 | # test suite. You never need to work with it otherwise. Remember that 8 | # your test database is "scratch space" for the test suite and is wiped 9 | # and recreated between test runs. Don't rely on the data there! 10 | config.cache_classes = true 11 | 12 | # Do not eager load code on boot. This avoids loading your whole application 13 | # just for the purpose of running a single test. If you are using a tool that 14 | # preloads Rails for running tests, you may have to set it to true. 15 | config.eager_load = false 16 | 17 | # Configure public file server for tests with Cache-Control for performance. 18 | # config.public_file_server.enabled = true 19 | # config.public_file_server.headers = { 20 | # 'Cache-Control' => 'public, max-age=3600' 21 | # } 22 | 23 | # Show full error reports and disable caching. 24 | config.consider_all_requests_local = true 25 | config.action_controller.perform_caching = false 26 | 27 | # Raise exceptions instead of rendering exception templates. 28 | config.action_dispatch.show_exceptions = false 29 | 30 | # Disable request forgery protection in test environment. 31 | config.action_controller.allow_forgery_protection = false 32 | 33 | # Tell Action Mailer not to deliver emails to the real world. 34 | # The :test delivery method accumulates sent emails in the 35 | # ActionMailer::Base.deliveries array. 36 | config.action_mailer.delivery_method = :test 37 | 38 | # Print deprecation notices to the stderr. 39 | config.active_support.deprecation = :stderr 40 | 41 | # Raises error for missing translations 42 | # config.action_view.raise_on_missing_translations = true 43 | end 44 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/application_controller_renderer.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # Be sure to restart your server when you modify this file. 3 | 4 | # ApplicationController.renderer.defaults.merge!( 5 | # http_host: 'example.org', 6 | # https: false 7 | # ) 8 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Be sure to restart your server when you modify this file. 4 | 5 | # Version of your assets, change this if you want to expire all your assets. 6 | Rails.application.config.assets.version = "1.0" 7 | 8 | # Add additional assets to the asset load path 9 | # Rails.application.config.assets.paths << Emoji.images_path 10 | 11 | # Precompile additional assets. 12 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. 13 | # Rails.application.config.assets.precompile += %w( search.js ) 14 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/audit-log.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | AuditLog.configure do 4 | # class name of you User model, default: 'User' 5 | # self.user_class = "User" 6 | # current_user method name in your Controller, default: 'current_user' 7 | self.current_user_method = "custom_current_user" 8 | end 9 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # Be sure to restart your server when you modify this file. 3 | 4 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 5 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 6 | 7 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 8 | # Rails.backtrace_cleaner.remove_silencers! 9 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/cookies_serializer.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Be sure to restart your server when you modify this file. 4 | 5 | # Specify a serializer for the signed and encrypted cookie jars. 6 | # Valid options are :json, :marshal, and :hybrid. 7 | Rails.application.config.action_dispatch.cookies_serializer = :marshal 8 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/devise.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Use this hook to configure devise mailer, warden hooks and so forth. 4 | # Many of these configuration options can be set straight in your model. 5 | Devise.setup do |config| 6 | # The secret key used by Devise. Devise uses this key to generate 7 | # random tokens. Changing this key will render invalid all existing 8 | # confirmation, reset password and unlock tokens in the database. 9 | # Devise will use the `secret_key_base` on Rails 4+ applications as its `secret_key` 10 | # by default. You can change it below and use your own secret key. 11 | config.secret_key = "1c78947326c696c7e3d762125951d64a160b7d84b1033c6b5c172422f222caea04cb5653cdd133d54595ede9563ca96db66fd1ccb0bb0d7bccdb3be499516e5c" 12 | 13 | # ==> Mailer Configuration 14 | # Configure the e-mail address which will be shown in Devise::Mailer, 15 | # note that it will be overwritten if you use your own mailer class 16 | # with default "from" parameter. 17 | config.mailer_sender = "please-change-me-at-config-initializers-devise@example.com" 18 | 19 | # Configure the class responsible to send e-mails. 20 | # config.mailer = 'Devise::Mailer' 21 | 22 | # ==> ORM configuration 23 | # Load and configure the ORM. Supports :active_record (default) and 24 | # :mongoid (bson_ext recommended) by default. Other ORMs may be 25 | # available as additional gems. 26 | require "devise/orm/active_record" 27 | 28 | # ==> Configuration for any authentication mechanism 29 | # Configure which keys are used when authenticating a user. The default is 30 | # just :email. You can configure it to use [:username, :subdomain], so for 31 | # authenticating a user, both parameters are required. Remember that those 32 | # parameters are used only when authenticating and not when retrieving from 33 | # session. If you need permissions, you should implement that in a before filter. 34 | # You can also supply a hash where the value is a boolean determining whether 35 | # or not authentication should be aborted when the value is not present. 36 | # config.authentication_keys = [:email] 37 | 38 | # Configure parameters from the request object used for authentication. Each entry 39 | # given should be a request method and it will automatically be passed to the 40 | # find_for_authentication method and considered in your model lookup. For instance, 41 | # if you set :request_keys to [:subdomain], :subdomain will be used on authentication. 42 | # The same considerations mentioned for authentication_keys also apply to request_keys. 43 | # config.request_keys = [] 44 | 45 | # Configure which authentication keys should be case-insensitive. 46 | # These keys will be downcased upon creating or modifying a user and when used 47 | # to authenticate or find a user. Default is :email. 48 | config.case_insensitive_keys = [:email] 49 | 50 | # Configure which authentication keys should have whitespace stripped. 51 | # These keys will have whitespace before and after removed upon creating or 52 | # modifying a user and when used to authenticate or find a user. Default is :email. 53 | config.strip_whitespace_keys = [:email] 54 | 55 | # Tell if authentication through request.params is enabled. True by default. 56 | # It can be set to an array that will enable params authentication only for the 57 | # given strategies, for example, `config.params_authenticatable = [:database]` will 58 | # enable it only for database (email + password) authentication. 59 | # config.params_authenticatable = true 60 | 61 | # Tell if authentication through HTTP Auth is enabled. False by default. 62 | # It can be set to an array that will enable http authentication only for the 63 | # given strategies, for example, `config.http_authenticatable = [:database]` will 64 | # enable it only for database authentication. The supported strategies are: 65 | # :database = Support basic authentication with authentication key + password 66 | # config.http_authenticatable = false 67 | 68 | # If 401 status code should be returned for AJAX requests. True by default. 69 | # config.http_authenticatable_on_xhr = true 70 | 71 | # The realm used in Http Basic Authentication. 'Application' by default. 72 | # config.http_authentication_realm = 'Application' 73 | 74 | # It will change confirmation, password recovery and other workflows 75 | # to behave the same regardless if the e-mail provided was right or wrong. 76 | # Does not affect registerable. 77 | # config.paranoid = true 78 | 79 | # By default Devise will store the user in session. You can skip storage for 80 | # particular strategies by setting this option. 81 | # Notice that if you are skipping storage for all authentication paths, you 82 | # may want to disable generating routes to Devise's sessions controller by 83 | # passing skip: :sessions to `devise_for` in your config/routes.rb 84 | config.skip_session_storage = [:http_auth] 85 | 86 | # By default, Devise cleans up the CSRF token on authentication to 87 | # avoid CSRF token fixation attacks. This means that, when using AJAX 88 | # requests for sign in and sign up, you need to get a new CSRF token 89 | # from the server. You can disable this option at your own risk. 90 | # config.clean_up_csrf_token_on_authentication = true 91 | 92 | # ==> Configuration for :database_authenticatable 93 | # For bcrypt, this is the cost for hashing the password and defaults to 10. If 94 | # using other encryptors, it sets how many times you want the password re-encrypted. 95 | # 96 | # Limiting the stretches to just one in testing will increase the performance of 97 | # your test suite dramatically. However, it is STRONGLY RECOMMENDED to not use 98 | # a value less than 10 in other environments. Note that, for bcrypt (the default 99 | # encryptor), the cost increases exponentially with the number of stretches (e.g. 100 | # a value of 20 is already extremely slow: approx. 60 seconds for 1 calculation). 101 | config.stretches = Rails.env.test? ? 1 : 10 102 | 103 | # Setup a pepper to generate the encrypted password. 104 | # config.pepper = 'b1a08aa7364dafb0a66452187bfb8a4859aa253e056ec5baaafeb3860d3416975a8145083227249d2585ef15c5b0f47f22d5493cd0d40b0f053849e824c3c7c7' 105 | 106 | # Send a notification email when the user's password is changed 107 | # config.send_password_change_notification = false 108 | 109 | # ==> Configuration for :confirmable 110 | # A period that the user is allowed to access the website even without 111 | # confirming their account. For instance, if set to 2.days, the user will be 112 | # able to access the website for two days without confirming their account, 113 | # access will be blocked just in the third day. Default is 0.days, meaning 114 | # the user cannot access the website without confirming their account. 115 | # config.allow_unconfirmed_access_for = 2.days 116 | 117 | # A period that the user is allowed to confirm their account before their 118 | # token becomes invalid. For example, if set to 3.days, the user can confirm 119 | # their account within 3 days after the mail was sent, but on the fourth day 120 | # their account can't be confirmed with the token any more. 121 | # Default is nil, meaning there is no restriction on how long a user can take 122 | # before confirming their account. 123 | # config.confirm_within = 3.days 124 | 125 | # If true, requires any email changes to be confirmed (exactly the same way as 126 | # initial account confirmation) to be applied. Requires additional unconfirmed_email 127 | # db field (see migrations). Until confirmed, new email is stored in 128 | # unconfirmed_email column, and copied to email column on successful confirmation. 129 | config.reconfirmable = true 130 | 131 | # Defines which key will be used when confirming an account 132 | # config.confirmation_keys = [:email] 133 | 134 | # ==> Configuration for :rememberable 135 | # The time the user will be remembered without asking for credentials again. 136 | # config.remember_for = 2.weeks 137 | 138 | # Invalidates all the remember me tokens when the user signs out. 139 | config.expire_all_remember_me_on_sign_out = true 140 | 141 | # If true, extends the user's remember period when remembered via cookie. 142 | # config.extend_remember_period = false 143 | 144 | # Options to be passed to the created cookie. For instance, you can set 145 | # secure: true in order to force SSL only cookies. 146 | # config.rememberable_options = {} 147 | 148 | # ==> Configuration for :validatable 149 | # Range for password length. 150 | config.password_length = 6..72 151 | 152 | # ==> Configuration for :timeoutable 153 | # The time you want to timeout the user session without activity. After this 154 | # time the user will be asked for credentials again. Default is 30 minutes. 155 | # config.timeout_in = 30.minutes 156 | 157 | # ==> Configuration for :lockable 158 | # Defines which strategy will be used to lock an account. 159 | # :failed_attempts = Locks an account after a number of failed attempts to sign in. 160 | # :none = No lock strategy. You should handle locking by yourself. 161 | # config.lock_strategy = :failed_attempts 162 | 163 | # Defines which key will be used when locking and unlocking an account 164 | # config.unlock_keys = [:email] 165 | 166 | # Defines which strategy will be used to unlock an account. 167 | # :email = Sends an unlock link to the user email 168 | # :time = Re-enables login after a certain amount of time (see :unlock_in below) 169 | # :both = Enables both strategies 170 | # :none = No unlock strategy. You should handle unlocking by yourself. 171 | # config.unlock_strategy = :both 172 | 173 | # Number of authentication tries before locking an account if lock_strategy 174 | # is failed attempts. 175 | # config.maximum_attempts = 20 176 | 177 | # Time interval to unlock the account if :time is enabled as unlock_strategy. 178 | # config.unlock_in = 1.hour 179 | 180 | # Warn on the last attempt before the account is locked. 181 | # config.last_attempt_warning = true 182 | 183 | # ==> Configuration for :recoverable 184 | # 185 | # Defines which key will be used when recovering the password for an account 186 | # config.reset_password_keys = [:email] 187 | 188 | # Time interval you can reset your password with a reset password key. 189 | # Don't put a too small interval or your users won't have the time to 190 | # change their passwords. 191 | config.reset_password_within = 6.hours 192 | 193 | # When set to false, does not sign a user in automatically after their password is 194 | # reset. Defaults to true, so a user is signed in automatically after a reset. 195 | # config.sign_in_after_reset_password = true 196 | 197 | # ==> Configuration for :encryptable 198 | # Allow you to use another encryption algorithm besides bcrypt (default). You can use 199 | # :sha1, :sha512 or encryptors from others authentication tools as :clearance_sha1, 200 | # :authlogic_sha512 (then you should set stretches above to 20 for default behavior) 201 | # and :restful_authentication_sha1 (then you should set stretches to 10, and copy 202 | # REST_AUTH_SITE_KEY to pepper). 203 | # 204 | # Require the `devise-encryptable` gem when using anything other than bcrypt 205 | # config.encryptor = :sha512 206 | 207 | # ==> Scopes configuration 208 | # Turn scoped views on. Before rendering "sessions/new", it will first check for 209 | # "users/sessions/new". It's turned off by default because it's slower if you 210 | # are using only default views. 211 | # config.scoped_views = false 212 | 213 | # Configure the default scope given to Warden. By default it's the first 214 | # devise role declared in your routes (usually :user). 215 | # config.default_scope = :user 216 | 217 | # Set this configuration to false if you want /users/sign_out to sign out 218 | # only the current scope. By default, Devise signs out all scopes. 219 | # config.sign_out_all_scopes = true 220 | 221 | # ==> Navigation configuration 222 | # Lists the formats that should be treated as navigational. Formats like 223 | # :html, should redirect to the sign in page when the user does not have 224 | # access, but formats like :xml or :json, should return 401. 225 | # 226 | # If you have any extra navigational formats, like :iphone or :mobile, you 227 | # should add them to the navigational formats lists. 228 | # 229 | # The "*/*" below is required to match Internet Explorer requests. 230 | # config.navigational_formats = ['*/*', :html] 231 | 232 | # The default HTTP method used to sign out a resource. Default is :delete. 233 | config.sign_out_via = :delete 234 | 235 | # ==> OmniAuth 236 | # Add a new OmniAuth provider. Check the wiki for more information on setting 237 | # up on your models and hooks. 238 | # config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo' 239 | 240 | # ==> Warden configuration 241 | # If you want to use other strategies, that are not supported by Devise, or 242 | # change the failure app, you can configure them inside the config.warden block. 243 | # 244 | # config.warden do |manager| 245 | # manager.intercept_401 = false 246 | # manager.default_strategies(scope: :user).unshift :some_external_strategy 247 | # end 248 | 249 | # ==> Mountable engine configurations 250 | # When using Devise inside an engine, let's call it `MyEngine`, and this engine 251 | # is mountable, there are some extra configurations to be taken into account. 252 | # The following options are available, assuming the engine is mounted as: 253 | # 254 | # mount MyEngine, at: '/my_engine' 255 | # 256 | # The router that invoked `devise_for`, in the example above, would be: 257 | # config.router_name = :my_engine 258 | # 259 | # When using OmniAuth, Devise cannot automatically set OmniAuth path, 260 | # so you need to do it manually. For the users scope, it would be: 261 | # config.omniauth_path_prefix = '/my_engine/users/auth' 262 | end 263 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Be sure to restart your server when you modify this file. 4 | 5 | # Configure sensitive parameters which will be filtered from the log file. 6 | Rails.application.config.filter_parameters += [:password] 7 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # Be sure to restart your server when you modify this file. 3 | 4 | # Add new inflection rules using the following format. Inflections 5 | # are locale specific, and you may define rules for as many different 6 | # locales as you wish. All of these examples are active by default: 7 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 8 | # inflect.plural /^(ox)$/i, '\1en' 9 | # inflect.singular /^(ox)en/i, '\1' 10 | # inflect.irregular 'person', 'people' 11 | # inflect.uncountable %w( fish sheep ) 12 | # end 13 | 14 | # These inflection rules are supported but not enabled by default: 15 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 16 | # inflect.acronym 'RESTful' 17 | # end 18 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # Be sure to restart your server when you modify this file. 3 | 4 | # Add new mime types for use in respond_to blocks: 5 | # Mime::Type.register "text/richtext", :rtf 6 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Be sure to restart your server when you modify this file. 4 | 5 | Rails.application.config.session_store :cookie_store, key: "_dummy_session" 6 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Be sure to restart your server when you modify this file. 4 | 5 | # This file contains settings for ActionController::ParamsWrapper which 6 | # is enabled by default. 7 | 8 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 9 | ActiveSupport.on_load(:action_controller) do 10 | wrap_parameters format: [:json] 11 | end 12 | 13 | # To enable root element in JSON for ActiveRecord objects. 14 | # ActiveSupport.on_load(:active_record) do 15 | # self.include_root_in_json = true 16 | # end 17 | -------------------------------------------------------------------------------- /test/dummy/config/locales/devise.en.yml: -------------------------------------------------------------------------------- 1 | # Additional translations at https://github.com/plataformatec/devise/wiki/I18n 2 | 3 | en: 4 | devise: 5 | confirmations: 6 | confirmed: "Your email address has been successfully confirmed." 7 | send_instructions: "You will receive an email with instructions for how to confirm your email address in a few minutes." 8 | send_paranoid_instructions: "If your email address exists in our database, you will receive an email with instructions for how to confirm your email address in a few minutes." 9 | failure: 10 | already_authenticated: "You are already signed in." 11 | inactive: "Your account is not activated yet." 12 | invalid: "Invalid %{authentication_keys} or password." 13 | locked: "Your account is locked." 14 | last_attempt: "You have one more attempt before your account is locked." 15 | not_found_in_database: "Invalid %{authentication_keys} or password." 16 | timeout: "Your session expired. Please sign in again to continue." 17 | unauthenticated: "You need to sign in or sign up before continuing." 18 | unconfirmed: "You have to confirm your email address before continuing." 19 | mailer: 20 | confirmation_instructions: 21 | subject: "Confirmation instructions" 22 | reset_password_instructions: 23 | subject: "Reset password instructions" 24 | unlock_instructions: 25 | subject: "Unlock instructions" 26 | password_change: 27 | subject: "Password Changed" 28 | omniauth_callbacks: 29 | failure: "Could not authenticate you from %{kind} because \"%{reason}\"." 30 | success: "Successfully authenticated from %{kind} account." 31 | passwords: 32 | no_token: "You can't access this page without coming from a password reset email. If you do come from a password reset email, please make sure you used the full URL provided." 33 | send_instructions: "You will receive an email with instructions on how to reset your password in a few minutes." 34 | send_paranoid_instructions: "If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes." 35 | updated: "Your password has been changed successfully. You are now signed in." 36 | updated_not_active: "Your password has been changed successfully." 37 | registrations: 38 | destroyed: "Bye! Your account has been successfully cancelled. We hope to see you again soon." 39 | signed_up: "Welcome! You have signed up successfully." 40 | signed_up_but_inactive: "You have signed up successfully. However, we could not sign you in because your account is not yet activated." 41 | signed_up_but_locked: "You have signed up successfully. However, we could not sign you in because your account is locked." 42 | signed_up_but_unconfirmed: "A message with a confirmation link has been sent to your email address. Please follow the link to activate your account." 43 | update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and follow the confirm link to confirm your new email address." 44 | updated: "Your account has been updated successfully." 45 | sessions: 46 | signed_in: "Signed in successfully." 47 | signed_out: "Signed out successfully." 48 | already_signed_out: "Signed out successfully." 49 | unlocks: 50 | send_instructions: "You will receive an email with instructions for how to unlock your account in a few minutes." 51 | send_paranoid_instructions: "If your account exists, you will receive an email with instructions for how to unlock it in a few minutes." 52 | unlocked: "Your account has been unlocked successfully. Please sign in to continue." 53 | errors: 54 | messages: 55 | already_confirmed: "was already confirmed, please try signing in" 56 | confirmation_period_expired: "needs to be confirmed within %{period}, please request a new one" 57 | expired: "has expired, please request a new one" 58 | not_found: "not found" 59 | not_locked: "was not locked" 60 | not_saved: 61 | one: "1 error prohibited this %{resource} from being saved:" 62 | other: "%{count} errors prohibited this %{resource} from being saved:" 63 | -------------------------------------------------------------------------------- /test/dummy/config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Files in the config/locales directory are used for internationalization 2 | # and are automatically loaded by Rails. If you want to use locales other 3 | # than English, add the necessary files in this directory. 4 | # 5 | # To use the locales, use `I18n.t`: 6 | # 7 | # I18n.t 'hello' 8 | # 9 | # In views, this is aliased to just `t`: 10 | # 11 | # <%= t('hello') %> 12 | # 13 | # To use a different locale, set it with `I18n.locale`: 14 | # 15 | # I18n.locale = :es 16 | # 17 | # This would use the information in config/locales/es.yml. 18 | # 19 | # To learn more, please read the Rails Internationalization guide 20 | # available at http://guides.rubyonrails.org/i18n.html. 21 | 22 | en: 23 | hello: "Hello world" 24 | audit_log: 25 | action: 26 | hello: "Hello1" 27 | home: "Visit Home" 28 | -------------------------------------------------------------------------------- /test/dummy/config/puma.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Puma can serve each request in a thread from an internal thread pool. 4 | # The `threads` method setting takes two numbers a minimum and maximum. 5 | # Any libraries that use thread pools should be configured to match 6 | # the maximum value specified for Puma. Default is set to 5 threads for minimum 7 | # and maximum, this matches the default thread size of Active Record. 8 | # 9 | threads_count = ENV.fetch("RAILS_MAX_THREADS", 5).to_i 10 | threads threads_count, threads_count 11 | 12 | # Specifies the `port` that Puma will listen on to receive requests, default is 3000. 13 | # 14 | port ENV.fetch("PORT", 3000) 15 | 16 | # Specifies the `environment` that Puma will run in. 17 | # 18 | environment ENV.fetch("RAILS_ENV", "development") 19 | 20 | # Specifies the number of `workers` to boot in clustered mode. 21 | # Workers are forked webserver processes. If using threads and workers together 22 | # the concurrency of the application would be max `threads` * `workers`. 23 | # Workers do not work on JRuby or Windows (both of which do not support 24 | # processes). 25 | # 26 | # workers ENV.fetch("WEB_CONCURRENCY") { 2 } 27 | 28 | # Use the `preload_app!` method when specifying a `workers` number. 29 | # This directive tells Puma to first boot the application and load code 30 | # before forking the application. This takes advantage of Copy On Write 31 | # process behavior so workers use less memory. If you use this option 32 | # you need to make sure to reconnect any threads in the `on_worker_boot` 33 | # block. 34 | # 35 | # preload_app! 36 | 37 | # The code in the `on_worker_boot` will be called if you are using 38 | # clustered mode by specifying a number of `workers`. After each worker 39 | # process is booted this block will be run, if you are using `preload_app!` 40 | # option you will want to use this block to reconnect to any threads 41 | # or connections that may have been created at application boot, Ruby 42 | # cannot share connections between processes. 43 | # 44 | # on_worker_boot do 45 | # ActiveRecord::Base.establish_connection if defined?(ActiveRecord) 46 | # end 47 | 48 | # Allow puma to be restarted by `rails restart` command. 49 | plugin :tmp_restart 50 | -------------------------------------------------------------------------------- /test/dummy/config/routes.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Rails.application.routes.draw do 4 | resources :comments 5 | resources :topics 6 | devise_for :users 7 | mount AuditLog::Engine => "/audit-log" 8 | root to: "welcome#index" 9 | end 10 | -------------------------------------------------------------------------------- /test/dummy/config/secrets.yml: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key is used for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | 6 | # Make sure the secret is at least 30 characters and all random, 7 | # no regular words or you'll be exposed to dictionary attacks. 8 | # You can use `rails secret` to generate a secure secret key. 9 | 10 | # Make sure the secrets in this file are kept private 11 | # if you're sharing your code publicly. 12 | 13 | development: 14 | secret_key_base: 5c58b96a81fa832d47ed3f82e4ddb743ffd25ef22559667a77c96518bbb736e1a240fb76b4b68b96a25c885934c236a7ccb1acc5e865fc8c35895faa4ccc4b60 15 | 16 | test: 17 | secret_key_base: 4c766db61f426d511a9087e8c064efd3efb472eeb7f296ab5134c8a93d352ceea75202cda9f75fc001a881204d1629039f688ef3917da6c1c87137713de1286f 18 | 19 | # Do not keep production secrets in the repository, 20 | # instead read values from the environment. 21 | production: 22 | secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> 23 | -------------------------------------------------------------------------------- /test/dummy/config/spring.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | %w[ 4 | .ruby-version 5 | .rbenv-vars 6 | tmp/restart.txt 7 | tmp/caching-dev.txt 8 | ].each { |path| Spring.watch(path) } 9 | -------------------------------------------------------------------------------- /test/dummy/db/migrate/20160321143003_devise_create_users.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class DeviseCreateUsers < ActiveRecord::Migration[5.0] 4 | def change 5 | create_table(:users) do |t| 6 | ## Database authenticatable 7 | t.string :email, null: false, default: "" 8 | t.string :encrypted_password, null: false, default: "" 9 | 10 | ## Recoverable 11 | t.string :reset_password_token 12 | t.datetime :reset_password_sent_at 13 | 14 | ## Rememberable 15 | t.datetime :remember_created_at 16 | 17 | ## Trackable 18 | t.integer :sign_in_count, default: 0, null: false 19 | t.datetime :current_sign_in_at 20 | t.datetime :last_sign_in_at 21 | t.string :current_sign_in_ip 22 | t.string :last_sign_in_ip 23 | 24 | ## Confirmable 25 | # t.string :confirmation_token 26 | # t.datetime :confirmed_at 27 | # t.datetime :confirmation_sent_at 28 | # t.string :unconfirmed_email # Only if using reconfirmable 29 | 30 | ## Lockable 31 | # t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts 32 | # t.string :unlock_token # Only if unlock strategy is :email or :both 33 | # t.datetime :locked_at 34 | 35 | t.timestamps null: false 36 | end 37 | 38 | add_index :users, :email, unique: true 39 | add_index :users, :reset_password_token, unique: true 40 | # add_index :users, :confirmation_token, unique: true 41 | # add_index :users, :unlock_token, unique: true 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /test/dummy/db/migrate/20160328070223_create_topics.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateTopics < ActiveRecord::Migration[5.0] 4 | def change 5 | create_table :topics do |t| 6 | t.string :title 7 | t.integer :user_id 8 | 9 | t.timestamps 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /test/dummy/db/migrate/20160328070302_create_comments.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateComments < ActiveRecord::Migration[5.0] 4 | def change 5 | create_table :comments do |t| 6 | t.integer :topic_id 7 | t.integer :user_id 8 | t.string :body 9 | 10 | t.timestamps 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /test/dummy/db/schema.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # This file is auto-generated from the current state of the database. Instead 4 | # of editing this file, please use the migrations feature of Active Record to 5 | # incrementally modify your database, and then regenerate this schema definition. 6 | # 7 | # This file is the source Rails uses to define your schema when running `bin/rails 8 | # db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to 9 | # be faster and is potentially less error prone than running all of your 10 | # migrations from scratch. Old migrations may fail to apply correctly if those 11 | # migrations use external dependencies or application code. 12 | # 13 | # It's strongly recommended that you check this file into your version control system. 14 | 15 | ActiveRecord::Schema.define(version: 20_190_527_035_005) do 16 | # These are extensions that must be enabled in order to support this database 17 | enable_extension "plpgsql" 18 | 19 | create_table "audit_logs", force: :cascade do |t| 20 | t.string "action", null: false 21 | t.bigint "user_id" 22 | t.bigint "record_id" 23 | t.string "record_type" 24 | t.text "payload" 25 | t.text "request" 26 | t.datetime "created_at" 27 | t.datetime "updated_at" 28 | t.index ["action"], name: "index_audit_logs_on_action" 29 | t.index %w[record_type record_id], name: "index_audit_logs_on_record_type_and_record_id" 30 | t.index %w[user_id action], name: "index_audit_logs_on_user_id_and_action" 31 | end 32 | 33 | create_table "comments", id: :serial, force: :cascade do |t| 34 | t.integer "topic_id" 35 | t.integer "user_id" 36 | t.string "body" 37 | t.datetime "created_at", null: false 38 | t.datetime "updated_at", null: false 39 | end 40 | 41 | create_table "topics", id: :serial, force: :cascade do |t| 42 | t.string "title" 43 | t.integer "user_id" 44 | t.datetime "created_at", null: false 45 | t.datetime "updated_at", null: false 46 | end 47 | 48 | create_table "users", id: :serial, force: :cascade do |t| 49 | t.string "email", default: "", null: false 50 | t.string "encrypted_password", default: "", null: false 51 | t.string "reset_password_token" 52 | t.datetime "reset_password_sent_at" 53 | t.datetime "remember_created_at" 54 | t.integer "sign_in_count", default: 0, null: false 55 | t.datetime "current_sign_in_at" 56 | t.datetime "last_sign_in_at" 57 | t.string "current_sign_in_ip" 58 | t.string "last_sign_in_ip" 59 | t.datetime "created_at", null: false 60 | t.datetime "updated_at", null: false 61 | t.index ["email"], name: "index_users_on_email", unique: true 62 | t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true 63 | end 64 | end 65 | -------------------------------------------------------------------------------- /test/dummy/db/seeds.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # This file should contain all the record creation needed to seed the database with its default values. 3 | # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). 4 | # 5 | # Examples: 6 | # 7 | # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) 8 | # Mayor.create(name: 'Emanuel', city: cities.first) 9 | -------------------------------------------------------------------------------- /test/dummy/lib/assets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rails-engine/audit-log/7fac678f007d9a7337a990f5ca7eb3d37351b477/test/dummy/lib/assets/.keep -------------------------------------------------------------------------------- /test/dummy/lib/tasks/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rails-engine/audit-log/7fac678f007d9a7337a990f5ca7eb3d37351b477/test/dummy/lib/tasks/.keep -------------------------------------------------------------------------------- /test/dummy/log/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rails-engine/audit-log/7fac678f007d9a7337a990f5ca7eb3d37351b477/test/dummy/log/.keep -------------------------------------------------------------------------------- /test/dummy/public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The page you were looking for doesn't exist.

62 |

You may have mistyped the address or the page may have moved.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /test/dummy/public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The change you wanted was rejected.

62 |

Maybe you tried to change something you didn't have access to.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /test/dummy/public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

We're sorry, but something went wrong.

62 |
63 |

If you are the application owner check the logs for more information.

64 |
65 | 66 | 67 | -------------------------------------------------------------------------------- /test/dummy/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rails-engine/audit-log/7fac678f007d9a7337a990f5ca7eb3d37351b477/test/dummy/public/favicon.ico -------------------------------------------------------------------------------- /test/dummy/public/robots.txt: -------------------------------------------------------------------------------- 1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file 2 | # 3 | # To ban all spiders from the entire site uncomment the next two lines: 4 | # User-agent: * 5 | # Disallow: / 6 | -------------------------------------------------------------------------------- /test/dummy/vendor/assets/javascripts/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rails-engine/audit-log/7fac678f007d9a7337a990f5ca7eb3d37351b477/test/dummy/vendor/assets/javascripts/.keep -------------------------------------------------------------------------------- /test/dummy/vendor/assets/stylesheets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rails-engine/audit-log/7fac678f007d9a7337a990f5ca7eb3d37351b477/test/dummy/vendor/assets/stylesheets/.keep -------------------------------------------------------------------------------- /test/factories/comments.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :comment, class: Comment do 5 | association :user, factory: :user 6 | association :topic, factory: :topic 7 | sequence(:body) { |n| "body#{n}" } 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /test/factories/logs.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :log, class: AuditLog::Log do 5 | association :user, factory: :user 6 | association :record, factory: :topic 7 | action { "create_topic" } 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /test/factories/topics.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :topic, class: Topic do 5 | association :user, factory: :user 6 | sequence(:title) { |n| "title#{n}" } 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /test/factories/users.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :user do 5 | sequence(:email) { |n| "user-#{n}@mail.com" } 6 | password { "password" } 7 | password_confirmation { "password" } 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /test/lib/audit_log_test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "test_helper" 4 | 5 | class AuditLogTest < ActiveSupport::TestCase 6 | test ".config" do 7 | assert_kind_of AuditLog::Configuration, AuditLog.config 8 | assert_equal "User", AuditLog.config.user_class 9 | assert_equal "custom_current_user", AuditLog.config.current_user_method 10 | assert_equal "name", AuditLog.config.user_name_method 11 | end 12 | 13 | test "audit!" do 14 | user = create(:user) 15 | record = create(:comment) 16 | request = ActionDispatch::Request.new(Rack::MockRequest.env_for("http://example.com:8080/test", 17 | "REMOTE_ADDR" => "10.10.10.10", 18 | "HTTP_USER_AGENT" => "Fake agent")) 19 | log = AuditLog.audit!(:hello, record, payload: { name: "Foo", status: 1 }, request: request, user: user) 20 | assert_equal false, log.new_record? 21 | 22 | log = AuditLog::Log.last 23 | assert_equal record, log.record 24 | assert_equal user, log.user 25 | assert_equal user.name, log.user_name 26 | assert_equal "Foo", log.payload["name"] 27 | assert_equal 1, log.payload["status"] 28 | assert_equal "10.10.10.10", log.request["ip"] 29 | assert_equal "http://example.com:8080/test", log.request["url"] 30 | assert_equal "Fake agent", log.request["user_agent"] 31 | assert_equal "hello", log.action 32 | assert_equal "Hello1", log.action_name 33 | end 34 | 35 | test "audit! with default" do 36 | log = AuditLog.audit!(:hello) 37 | assert_equal false, log.new_record? 38 | 39 | log = AuditLog::Log.last 40 | assert_nil log.user 41 | assert_nil log.record 42 | assert_equal "none", log.user_name 43 | assert_equal "hello", log.action 44 | assert_equal({}, log.payload) 45 | assert_equal({}, log.request) 46 | end 47 | 48 | test "audit! with JSON payload" do 49 | log = AuditLog.audit!(:hello, nil, payload: { "name" => "Foo" }.as_json) 50 | assert_equal false, log.new_record? 51 | 52 | log = AuditLog::Log.last 53 | assert_equal "Foo", log.payload["name"] 54 | end 55 | 56 | test "audit! with ActionController::Parameters payload" do 57 | params = ActionController::Parameters.new(a: "123", b: "456") 58 | params.permit! 59 | log = AuditLog.audit!(:hello, nil, payload: params) 60 | assert_equal false, log.new_record? 61 | 62 | log = AuditLog::Log.last 63 | assert_equal "123", log.payload["a"] 64 | assert_equal "456", log.payload["b"] 65 | end 66 | 67 | test "action_options" do 68 | assert_equal [["List Audit Log", "list_audit_log"], ["Create Audit Log", "create_audit_log"], ["Update Audit Log", "update_audit_log"], ["Update Password", "update_password"], %w[Hello1 hello], ["Visit Home", "home"]], 69 | AuditLog.action_options 70 | end 71 | end 72 | -------------------------------------------------------------------------------- /test/models/log_test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "test_helper" 4 | 5 | module AuditLog 6 | class LogTest < ActiveSupport::TestCase 7 | test "initialize_payload_request" do 8 | log = AuditLog::Log.new 9 | assert_equal({}, log.request) 10 | assert_equal({}, log.payload) 11 | 12 | log = AuditLog::Log.new(payload: { foo: 1 }) 13 | assert_equal({ "foo" => 1 }, log.payload) 14 | 15 | log = AuditLog::Log.new(request: { user_agent: "Hello world" }) 16 | assert_equal({ "user_agent" => "Hello world" }, log.request) 17 | end 18 | 19 | test "create" do 20 | user = create(:user) 21 | topic = create(:topic) 22 | 23 | log = create(:log, action: "create_topic", record: topic, user: user, 24 | payload: { id: topic.id, title: topic.title }, request: { ip: "0.0.0.0" }) 25 | assert_equal false, log.new_record? 26 | 27 | assert_equal "create_topic", log.action 28 | assert_equal topic, log.record 29 | assert_equal user, log.user 30 | assert_equal topic.id, log.payload["id"] 31 | assert_equal topic.title, log.payload["title"] 32 | assert_equal "0.0.0.0", log.request["ip"] 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Configure Rails Environment 4 | ENV["RAILS_ENV"] = "test" 5 | 6 | require_relative "../test/dummy/config/environment" 7 | ActiveRecord::Migrator.migrations_paths = [File.expand_path("../test/dummy/db/migrate", __dir__)] 8 | require "rails/test_help" 9 | 10 | # Filter out the backtrace from minitest while preserving the one from other libraries. 11 | Minitest.backtrace_filter = Minitest::BacktraceFilter.new 12 | 13 | require "rails/test_unit/reporter" 14 | Rails::TestUnitReporter.executable = "bin/test" 15 | 16 | require "factory_bot" 17 | FactoryBot.definition_file_paths = [File.expand_path("factories", __dir__)] 18 | FactoryBot.find_definitions 19 | 20 | require "audit-log" 21 | 22 | # Load fixtures from the engine 23 | if ActiveSupport::TestCase.respond_to?(:fixture_path=) 24 | ActiveSupport::TestCase.fixture_path = File.expand_path("fixtures", __dir__) 25 | ActionDispatch::IntegrationTest.fixture_path = ActiveSupport::TestCase.fixture_path 26 | ActiveSupport::TestCase.file_fixture_path = "#{ActiveSupport::TestCase.fixture_path}/files" 27 | ActiveSupport::TestCase.fixtures :all 28 | end 29 | 30 | # Load fixtures from the engine 31 | module ActiveSupport 32 | class TestCase 33 | include FactoryBot::Syntax::Methods 34 | end 35 | end 36 | 37 | module ActionView 38 | class TestCase 39 | include Rails.application.routes.url_helpers 40 | end 41 | end 42 | 43 | module ActionDispatch 44 | class IntegrationTest 45 | def sign_in(user) 46 | post main_app.user_session_path \ 47 | "user[email]" => user.email, 48 | "user[password]" => user.password 49 | end 50 | 51 | def sign_in_session(user) 52 | open_session do |app| 53 | app.post main_app.user_session_path \ 54 | "user[email]" => user.email, 55 | "user[password]" => user.password 56 | assert app.controller.user_signed_in?, "login_with_session #{user.email} 没有成功, #{app.flash[:alert]}" 57 | end 58 | end 59 | 60 | def assert_required_user 61 | assert_response :redirect 62 | assert_equal "You need to sign in or sign up before continuing.", flash[:alert] 63 | end 64 | 65 | def assert_access_denied 66 | assert_response :redirect 67 | assert_equal "Access denied.", flash[:alert] 68 | end 69 | end 70 | end 71 | --------------------------------------------------------------------------------