tamaudit 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +57 -0
- data/Rakefile +31 -0
- data/app/models/tamaudit/audit.rb +44 -0
- data/config/database.yml +24 -0
- data/config/routes.rb +2 -0
- data/db/migrate/20131029200927_create_auditable_audits.rb +14 -0
- data/lib/tamaudit.rb +20 -0
- data/lib/tamaudit/auditor.rb +7 -0
- data/lib/tamaudit/auditor_behavior.rb +98 -0
- data/lib/tamaudit/auditor_request.rb +13 -0
- data/lib/tamaudit/engine.rb +19 -0
- data/lib/tamaudit/version.rb +3 -0
- data/lib/tasks/tamaudit_tasks.rake +4 -0
- data/spec/controllers/audits_controller_spec.rb +47 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/javascripts/general_controller.js +2 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/assets/stylesheets/general_controller.css +4 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/controllers/general_controller_controller.rb +2 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/helpers/general_controller_helper.rb +2 -0
- data/spec/dummy/app/models/general_model.rb +4 -0
- data/spec/dummy/app/models/user.rb +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +23 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +29 -0
- data/spec/dummy/config/environments/production.rb +80 -0
- data/spec/dummy/config/environments/test.rb +36 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +12 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +4 -0
- data/spec/dummy/db/migrate/20131029211126_create_general_models.rb +12 -0
- data/spec/dummy/db/migrate/20131030014901_create_users.rb +11 -0
- data/spec/dummy/db/schema.rb +52 -0
- data/spec/dummy/public/404.html +58 -0
- data/spec/dummy/public/422.html +58 -0
- data/spec/dummy/public/500.html +57 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/factories/auditable_audits.rb +11 -0
- data/spec/factories/general_models.rb +10 -0
- data/spec/factories/users.rb +9 -0
- data/spec/models/models/general_model_spec.rb +206 -0
- data/spec/models/models/user_spec.rb +5 -0
- data/spec/models/tattletale/audit_spec.rb +8 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/support/models.rb +8 -0
- data/spec/support/schema.rb +34 -0
- metadata +283 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 803deb0c93b4f7f8396d2c975b23def4389011c3
|
4
|
+
data.tar.gz: fe511e53d190731f17d7a60a844bdcd341085eca
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 76180c393d507d6b02eeed2e7bac52597d2e35d9d7e5266867d1ade0fdc77b8d39e3dfa53253ea00bf0a03843a925958dc34b975dabbc6a244b6956002c22730
|
7
|
+
data.tar.gz: 09a34a28dc8fbe14422d074cb5c97f9fac0ea9368b5f3e26ed377e30fc0b5d0c4ba6eb19c7629533bcd80f566a3e099bc3e149eb8f70f1cbb2572db74a2049de
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2013 continuum.cl
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# Tamaudit - IN PROGRESS
|
2
|
+
|
3
|
+
## Audits activerecord models like a boss
|
4
|
+
|
5
|
+
|
6
|
+
Audit activerecord models like a boss. Tested in rails 4 and ruby 2.0.0.
|
7
|
+
|
8
|
+
This project is heavily based in Espinita gem (https://github.com/continuum/espinita).
|
9
|
+
|
10
|
+
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
|
14
|
+
In your gemfile
|
15
|
+
|
16
|
+
gem "tamaudit"
|
17
|
+
|
18
|
+
In console
|
19
|
+
|
20
|
+
$ rake tamaudit:install:migrations
|
21
|
+
$ rake db:migrate
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
class Post < ActiveRecord::Base
|
26
|
+
auditable
|
27
|
+
end
|
28
|
+
|
29
|
+
@post.create(title: "an awesome blog post" )
|
30
|
+
|
31
|
+
Tamaudit will create an audit by default on creation , edition and destroy:
|
32
|
+
|
33
|
+
@post.audits.size #=> 1
|
34
|
+
|
35
|
+
Tamaudit provides options to include or exclude columns to trigger the creation of audit.
|
36
|
+
|
37
|
+
class Post < ActiveRecord::Base
|
38
|
+
auditable only: [:title] # except: [:some_column]
|
39
|
+
end
|
40
|
+
|
41
|
+
And lets you declare the callbacks you want for audit creation:
|
42
|
+
|
43
|
+
class Post < ActiveRecord::Base
|
44
|
+
auditable on: [:create] # on: [:create, :update]
|
45
|
+
end
|
46
|
+
|
47
|
+
You can find the audits records easily:
|
48
|
+
|
49
|
+
@post.audits.first #=> #<Tamaudit::Audit id: 1, auditable_id: 1, auditable_type: "Post", user_id: 1, user_type: "User", audited_changes: {"title"=>[nil, "MyString"], "created_at"=>[nil, 2013-10-30 15:50:14 UTC], "updated_at"=>[nil, 2013-10-30 15:50:14 UTC], "id"=>[nil, 1]}
|
50
|
+
|
51
|
+
Tamaudit will save the model changes in a serialized column called audited_changes:
|
52
|
+
|
53
|
+
@post.audits.first.audited_changes #=> {"title"=>[nil, "MyString"], "created_at"=>[nil, 2013-10-30 15:50:14 UTC], "updated_at"=>[nil, 2013-10-30 15:50:14 UTC], "id"=>[nil, 1]}
|
54
|
+
|
55
|
+
Tamaudit will detect the current user when records saved from rails controllers. By default Tamaudit uses current_user method but you can change it:
|
56
|
+
|
57
|
+
Tamaudit.current_user_method = :authenticated_user
|
data/Rakefile
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
#begin
|
2
|
+
# require 'bundler/setup'
|
3
|
+
#rescue LoadError
|
4
|
+
# puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
#end
|
6
|
+
|
7
|
+
|
8
|
+
require 'rspec/core/rake_task'
|
9
|
+
require 'bundler'
|
10
|
+
Bundler::GemHelper.install_tasks
|
11
|
+
|
12
|
+
desc 'Default: run unit specs.'
|
13
|
+
task :default => :spec
|
14
|
+
|
15
|
+
desc 'Test the lazy_high_charts plugin.'
|
16
|
+
RSpec::Core::RakeTask.new('spec') do |t|
|
17
|
+
t.pattern = FileList['spec/**/*_spec.rb']
|
18
|
+
end
|
19
|
+
|
20
|
+
require 'rdoc/task'
|
21
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
22
|
+
rdoc.rdoc_dir = 'rdoc'
|
23
|
+
rdoc.title = 'Tamaudit'
|
24
|
+
rdoc.options << '--line-numbers'
|
25
|
+
rdoc.rdoc_files.include('README.rdoc')
|
26
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
27
|
+
end
|
28
|
+
|
29
|
+
#APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
|
30
|
+
#load 'rails/tasks/engine.rake'
|
31
|
+
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Tamaudit
|
2
|
+
class Audit < ActiveRecord::Base
|
3
|
+
|
4
|
+
self.table_name = 'audits'
|
5
|
+
|
6
|
+
belongs_to :auditable, polymorphic: true
|
7
|
+
belongs_to :user, polymorphic: true
|
8
|
+
|
9
|
+
|
10
|
+
scope :descending, ->{ reorder("version DESC")}
|
11
|
+
scope :creates, ->{ where({:action => 'create'})}
|
12
|
+
scope :updates, ->{ where({:action => 'update'})}
|
13
|
+
scope :destroys, ->{ where({:action => 'destroy'})}
|
14
|
+
|
15
|
+
scope :up_until, ->(date_or_time){where("created_at <= ?", date_or_time) }
|
16
|
+
scope :from_version, ->(version){where(['version >= ?', version]) }
|
17
|
+
scope :to_version, ->(version){where(['version <= ?', version]) }
|
18
|
+
scope :auditable_finder, ->(auditable_id, auditable_type){where(auditable_id: auditable_id, auditable_type: auditable_type)}
|
19
|
+
|
20
|
+
serialize :audited_changes
|
21
|
+
|
22
|
+
before_create :set_version_number, :set_audit_user
|
23
|
+
|
24
|
+
# Return all audits older than the current one.
|
25
|
+
def ancestors
|
26
|
+
self.class.where(['auditable_id = ? and auditable_type = ? and version <= ?',
|
27
|
+
auditable_id, auditable_type, version])
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
def set_version_number
|
32
|
+
max = self.class.auditable_finder(auditable_id, auditable_type).maximum(:version) || 0
|
33
|
+
self.version = max + 1
|
34
|
+
end
|
35
|
+
|
36
|
+
def set_audit_user
|
37
|
+
self.user = RequestStore.store[:audited_user] if RequestStore.store[:audited_user]
|
38
|
+
self.remote_address = RequestStore.store[:audited_ip] if RequestStore.store[:audited_ip]
|
39
|
+
|
40
|
+
nil # prevent stopping callback chains
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
data/config/database.yml
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
sqlite3mem: &SQLITE3MEM
|
2
|
+
adapter: sqlite3
|
3
|
+
database: ":memory:"
|
4
|
+
|
5
|
+
sqlite3: &SQLITE
|
6
|
+
adapter: sqlite3
|
7
|
+
database: audited_test.sqlite3.db
|
8
|
+
|
9
|
+
postgresql: &POSTGRES
|
10
|
+
adapter: postgresql
|
11
|
+
username: postgres
|
12
|
+
password: postgres
|
13
|
+
database: audited_test
|
14
|
+
min_messages: ERROR
|
15
|
+
|
16
|
+
mysql: &MYSQL
|
17
|
+
adapter: mysql
|
18
|
+
host: localhost
|
19
|
+
username: root
|
20
|
+
password:
|
21
|
+
database: audited_test
|
22
|
+
|
23
|
+
test:
|
24
|
+
<<: *<%= ENV['DB'] || 'SQLITE3MEM' %>
|
data/config/routes.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
class CreateAuditableAudits < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :audits do |t|
|
4
|
+
t.references :auditable, polymorphic: true, index: true
|
5
|
+
t.references :user, polymorphic: true, index: true
|
6
|
+
t.text :audited_changes
|
7
|
+
t.string :comment
|
8
|
+
t.integer :version
|
9
|
+
t.string :action
|
10
|
+
t.string :remote_address
|
11
|
+
t.timestamps
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/tamaudit.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require "tamaudit/engine"
|
2
|
+
require "request_store"
|
3
|
+
|
4
|
+
module Tamaudit
|
5
|
+
|
6
|
+
autoload :Auditor, "tamaudit/auditor"
|
7
|
+
autoload :AuditorBehavior, "tamaudit/auditor_behavior"
|
8
|
+
autoload :AuditorRequest, "tamaudit/auditor_request"
|
9
|
+
|
10
|
+
class << self
|
11
|
+
|
12
|
+
attr_accessor :current_user_method
|
13
|
+
|
14
|
+
def current_user_method
|
15
|
+
@current_user_method ||= :current_user
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module Tamaudit
|
2
|
+
module AuditorBehavior
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
class_attribute :excluded_cols
|
7
|
+
class_attribute :audit_callbacks
|
8
|
+
attr_accessor :audit_comment
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
|
13
|
+
@@default_excluded = %w(lock_version created_at updated_at created_on updated_on)
|
14
|
+
|
15
|
+
def auditable(options = {})
|
16
|
+
|
17
|
+
self.audit_callbacks = []
|
18
|
+
self.audit_callbacks << options[:on] unless options[:on].blank?
|
19
|
+
self.audit_callbacks.flatten!
|
20
|
+
|
21
|
+
after_create :audit_create if self.audit_callbacks.blank? || self.audit_callbacks.include?(:create)
|
22
|
+
before_update :audit_update if self.audit_callbacks.blank? || self.audit_callbacks.include?(:update)
|
23
|
+
before_destroy :audit_destroy if self.audit_callbacks.blank? || self.audit_callbacks.include?(:destroy)
|
24
|
+
|
25
|
+
self.excluded_cols = (@@default_excluded)
|
26
|
+
|
27
|
+
if options[:only]
|
28
|
+
options[:only] = [options[:only]].flatten.map { |x| x.to_s }
|
29
|
+
self.excluded_cols = (self.column_names - options[:only] )
|
30
|
+
end
|
31
|
+
|
32
|
+
if options[:except]
|
33
|
+
options[:except] = [options[:except]].flatten.map { |x| x.to_s }
|
34
|
+
self.excluded_cols = (@@default_excluded) + options[:except]
|
35
|
+
end
|
36
|
+
|
37
|
+
has_many :audits, :as => :auditable, :class_name => Tamaudit::Audit.name
|
38
|
+
#attr_accessor :audited_user, :audited_ip
|
39
|
+
accepts_nested_attributes_for :audits
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
def permited_columns
|
44
|
+
self.column_names - self.excluded_cols.to_a
|
45
|
+
end
|
46
|
+
|
47
|
+
# All audits made during the block called will be recorded as made
|
48
|
+
# by +user+. This method is hopefully threadsafe, making it ideal
|
49
|
+
# for background operations that require audit information.
|
50
|
+
def as_user(user, &block)
|
51
|
+
RequestStore.store[:audited_user] = user
|
52
|
+
yield
|
53
|
+
ensure
|
54
|
+
RequestStore.store[:audited_user] = nil
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
# audited attributes detected against permited columns
|
60
|
+
def audited_attributes
|
61
|
+
self.changes.keys & self.class.permited_columns
|
62
|
+
end
|
63
|
+
|
64
|
+
def audited_hash
|
65
|
+
Hash[ audited_attributes.map{|o| [o.to_sym, self.changes[o.to_sym] ] } ]
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
def audit_create
|
70
|
+
#puts self.class.audit_callbacks
|
71
|
+
write_audit(:action => 'create',
|
72
|
+
:audited_changes => audited_hash,
|
73
|
+
:comment => audit_comment)
|
74
|
+
end
|
75
|
+
|
76
|
+
def audit_update
|
77
|
+
#puts self.class.audit_callbacks
|
78
|
+
write_audit(:action => 'update',
|
79
|
+
:audited_changes => audited_hash,
|
80
|
+
:comment => audit_comment)
|
81
|
+
end
|
82
|
+
|
83
|
+
def audit_destroy
|
84
|
+
write_audit(:action => 'destroy',
|
85
|
+
:audited_changes => audited_hash,
|
86
|
+
:comment => audit_comment)
|
87
|
+
end
|
88
|
+
|
89
|
+
def write_audit(options)
|
90
|
+
if options[:action] == 'destroy'
|
91
|
+
self.audits.create(options)
|
92
|
+
else
|
93
|
+
self.audits.create(options) unless audited_hash.blank?
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Tamaudit::AuditorRequest
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
included do
|
5
|
+
before_filter :store_audited_user
|
6
|
+
end
|
7
|
+
|
8
|
+
def store_audited_user
|
9
|
+
RequestStore.store[:audited_user] = self.send(Tamaudit.current_user_method) #current_user
|
10
|
+
|
11
|
+
RequestStore.store[:audited_ip] = self.try(:request).try(:remote_ip)
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Tamaudit
|
2
|
+
class Engine < ::Rails::Engine
|
3
|
+
isolate_namespace Tamaudit
|
4
|
+
|
5
|
+
config.generators do |g|
|
6
|
+
g.test_framework :rspec,
|
7
|
+
:fixture_replacement => :factory_girl ,
|
8
|
+
:dir => "spec/factories"
|
9
|
+
g.integration_tool :rspec
|
10
|
+
end
|
11
|
+
|
12
|
+
initializer "include Auditor request into action controller" do |app|
|
13
|
+
ActionController::Base.send(:include, Tamaudit::AuditorRequest)
|
14
|
+
ActiveRecord::Base.send(:include, Tamaudit::Auditor)
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class AuditsController < ActionController::Base
|
4
|
+
def audit
|
5
|
+
@general_model = FactoryGirl.create(:general_model)
|
6
|
+
render :nothing => true
|
7
|
+
end
|
8
|
+
|
9
|
+
def update_user
|
10
|
+
current_user.update_attributes( :password => 'foo')
|
11
|
+
render :nothing => true
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
attr_accessor :current_user
|
17
|
+
attr_accessor :custom_user
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
describe AuditsController do
|
22
|
+
|
23
|
+
before :each do
|
24
|
+
GeneralModel.auditable
|
25
|
+
end
|
26
|
+
|
27
|
+
let( :general_model ){
|
28
|
+
FactoryFirl.create(:general_model)
|
29
|
+
}
|
30
|
+
|
31
|
+
let( :user ) { FactoryGirl.create(:user) }
|
32
|
+
|
33
|
+
describe "POST audit" do
|
34
|
+
|
35
|
+
it "should audit user" do
|
36
|
+
controller.send(:current_user=, user)
|
37
|
+
expect {
|
38
|
+
post :audit
|
39
|
+
}.to change( Tamaudit::Audit, :count )
|
40
|
+
|
41
|
+
assigns(:general_model).audits.last.user.should == user
|
42
|
+
assigns(:general_model).audits.last.remote_address.should == "0.0.0.0"
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
== README
|
2
|
+
|
3
|
+
This README would normally document whatever steps are necessary to get the
|
4
|
+
application up and running.
|
5
|
+
|
6
|
+
Things you may want to cover:
|
7
|
+
|
8
|
+
* Ruby version
|
9
|
+
|
10
|
+
* System dependencies
|
11
|
+
|
12
|
+
* Configuration
|
13
|
+
|
14
|
+
* Database creation
|
15
|
+
|
16
|
+
* Database initialization
|
17
|
+
|
18
|
+
* How to run the test suite
|
19
|
+
|
20
|
+
* Services (job queues, cache servers, search engines, etc.)
|
21
|
+
|
22
|
+
* Deployment instructions
|
23
|
+
|
24
|
+
* ...
|
25
|
+
|
26
|
+
|
27
|
+
Please feel free to use a different markup language if you do not plan to run
|
28
|
+
<tt>rake doc:app</tt>.
|