Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

First steps towards version 2

  • Loading branch information...
commit 581d82678e870dd983df8dc5c12805600b1ef743 1 parent c6ea638
@kunklejr authored
View
5 .gitignore
@@ -1,3 +1,6 @@
coverage
rdoc
-auditor-*.gem
+*.gem
+.bundle
+Gemfile.lock
+pkg/*
View
4 Gemfile
@@ -0,0 +1,4 @@
+source "http://rubygems.org"
+
+# Specify your gem's dependencies in auditor.gemspec
+gemspec
View
10 Rakefile
@@ -3,6 +3,9 @@ $:.unshift File.expand_path("../lib", __FILE__)
require 'rake'
require 'rake/rdoctask'
require 'rspec/core/rake_task'
+require 'bundler'
+
+Bundler::GemHelper.install_tasks
desc 'Default: run specs'
task :default => :spec
@@ -28,10 +31,3 @@ Rake::RDocTask.new(:rdoc) do |rdoc|
rdoc.rdoc_files.include('lib/**/*.rb')
end
-task :build do
- system "gem build auditor.gemspec"
-end
-
-task :release => :build do
- system "gem push auditor-#{Auditor::VERSION}"
-end
View
29 auditor.gemspec
@@ -1,24 +1,19 @@
# -*- encoding: utf-8 -*-
-lib = File.expand_path('../lib/', __FILE__)
-$:.unshift lib unless $:.include?(lib)
-
-require 'auditor/version'
-
+$:.push File.expand_path("../lib", __FILE__)
+require "auditor/version"
+
Gem::Specification.new do |s|
s.name = "auditor"
s.version = Auditor::VERSION
s.platform = Gem::Platform::RUBY
- s.authors = ["Jeff Kunkle", "Matt Wizeman"]
+ s.authors = ["Jeff Kunkle"]
s.homepage = "http://github.com/nearinfinity/auditor"
- s.summary = "Rails 3 plugin for auditing access to your ActiveRecord model objects"
- s.description = "Auditor allows you to declaratively specify what CRUD operations should be audited and save the audit data to the database."
+ s.summary = %q{Rails 3 plugin for auditing access to your ActiveRecord model objects}
+ s.description = %q{Auditor allows you to declaratively specify what CRUD operations should be audited and save the audit data to the database.}
s.license = "MIT"
-
- s.required_rubygems_version = ">= 1.3.6"
-
- s.add_development_dependency "rspec"
-
- s.files = Dir.glob("{lib}/**/*") + %w(LICENSE README.rdoc)
- s.test_files = Dir.glob("{spec}/**/*")
- s.require_path = 'lib'
-end
+
+ s.files = `git ls-files`.split("\n")
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
+ s.require_paths = ["lib"]
+end
View
25 lib/auditor.rb
@@ -1,9 +1,26 @@
require 'auditor/audit'
-require 'auditor/integration'
-require 'auditor/model_audit'
+require 'auditor/status'
+require 'auditor/config_parser'
+require 'auditor/recorder'
require 'auditor/user'
-require 'auditor/version'
module Auditor
- class Error < StandardError; end
+ include Status
+
+ def self.included(base)
+ base.extend(ClassMethods)
+ end
+
+ module ClassMethods
+ def audit(*args, &blk)
+ actions, options = ConfigParser.extract_config(args)
+
+ actions.each do |action|
+ recorder = Recorder.new(options, &blk)
+ send "before_#{action}", recorder unless action.to_sym == :find
+ send "after_#{action}", recorder
+ end
+ end
+ end
end
+
View
9 lib/auditor/audit.rb
@@ -1,6 +1,9 @@
require 'active_record'
-class Audit < ActiveRecord::Base
- validates_presence_of :auditable_id, :auditable_type, :user_id, :user_type, :action
- serialize :edits
+module Auditor
+ class Audit < ActiveRecord::Base
+ table_name :audits
+ validates_presence_of :auditable_id, :auditable_type, :user_id, :user_type, :action
+ serialize :edits
+ end
end
View
24 lib/auditor/config_parser.rb
@@ -1,22 +1,22 @@
module Auditor
class ConfigParser
-
+
def self.extract_config(args)
- options = (args.delete_at(args.size - 1) if args.last.kind_of?(Hash)) || {}
+ options = (args.pop if args.last.kind_of?(Hash)) || {}
normalize_config args, options
validate_config args, options
options = normalize_options(options)
-
+
[args, options]
end
-
+
private
-
+
def self.normalize_config(actions, options)
actions.each_with_index { |item, index| actions[index] = item.to_sym }
options.each_pair { |k, v| options[k.to_sym] = options.delete(k) unless k.kind_of? Symbol }
end
-
+
def self.normalize_options(options)
return { :except => [], :only => [] } if options.nil? || options.empty?
options[:except] = options[:except] || []
@@ -25,12 +25,12 @@ def self.normalize_options(options)
options[:only] = Array(options[:only]).map(&:to_s)
options
end
-
+
def self.validate_config(actions, options)
- raise Auditor::Error.new "at least one :create, :find, :update, or :destroy action must be specified" if actions.empty?
- raise Auditor::Error.new ":create, :find, :update, and :destroy are the only valid actions" unless actions.all? { |a| [:create, :find, :update, :destroy].include? a }
- raise Auditor::Error.new "only one of :except and :only can be specified" if options.size > 1
+ raise StandardError.new "at least one :create, :find, :update, or :destroy action must be specified" if actions.empty?
+ raise StandardError.new ":create, :find, :update, and :destroy are the only valid actions" unless actions.all? { |a| [:create, :find, :update, :destroy].include? a }
+ raise StandardError.new "only one of :except and :only can be specified" if options.size > 1
end
-
+
end
-end
+end
View
47 lib/auditor/model_audit.rb
@@ -1,47 +0,0 @@
-require 'auditor/thread_status'
-require 'auditor/config_parser'
-require 'auditor/recorder'
-
-module Auditor
- module ModelAudit
-
- def self.included(base)
- base.extend ClassMethods
- end
-
- # ActiveRecord won't call the after_find handler unless it see's a specific after_find method defined
- def after_find; end
-
- def auditor_disabled?
- Auditor::ThreadStatus.disabled? || @auditor_disabled
- end
-
- module ClassMethods
- def audit(*args, &blk)
- actions, options = Auditor::ConfigParser.extract_config(args)
-
- actions.each do |action|
- unless action.to_sym == :find
- callback = "auditor_before_#{action}"
- define_method(callback) do
- @auditor_auditor = Auditor::Recorder.new(action, self, options, &blk)
- @auditor_auditor.audit_before unless auditor_disabled?
- true
- end
- send "before_#{action}".to_sym, callback
- end
-
- callback = "auditor_after_#{action}"
- define_method(callback) do
- @auditor_auditor = Auditor::Recorder.new(action, self, options, &blk) if action.to_sym == :find
- @auditor_auditor.audit_after unless auditor_disabled?
- true
- end
- send "after_#{action}".to_sym, callback
-
- end
- end
- end
-
- end
-end
View
83 lib/auditor/recorder.rb
@@ -1,44 +1,67 @@
-require 'auditor/user'
+require 'auditor/status'
module Auditor
class Recorder
-
- def initialize(action, model, options, &blk)
- @action, @model, @options, @blk = action.to_sym, model, options, blk
+ include Status
+
+ def initialize(options, &blk)
+ @options = options
+ @blk = blk
+ end
+
+ def after_find(model)
+ @audit = Audit.new
end
-
- def audit_before
- @audit = Audit.new(:edits => prepare_edits(@model.changes, @options))
+
+ private
+
+ def user
+ Auditor::User.current_user
end
- def audit_after
- @audit ||= Audit.new
-
+ def audit_before(model)
+ @audit = Audit.new(:audited_changes => prepare_changes(model.changes))
+ end
+
+ def audit_after(model, action)
+ return true if auditor_disabled?
+
@audit.attributes = {
- :auditable_id => @model.id,
- :auditable_type => @model.class.to_s,
+ :auditable_id => model.id,
+ :auditable_type => model.class.to_s,
:user_id => user.id,
:user_type => user.class.to_s,
- :action => @action.to_s
+ :action => action.to_s
}
-
- @audit.auditable_version = @model.version if @model.respond_to? :version
- @audit.message = @blk.call(@model, user) if @blk
- @audit.save
+ @audit.auditable_version = model.version if model.respond_to?(:version)
+ @audit.comment = @blk.call(model, user) if @blk
+
+ # TODO: Make the bang a configurable option
+ @audit.save!
end
-
- private
- def user
- Auditor::User.current_user
- end
-
- def prepare_edits(changes, options)
- chg = changes.dup
- chg = chg.delete_if { |key, value| options[:except].include? key } unless options[:except].empty?
- chg = chg.delete_if { |key, value| !options[:only].include? key } unless options[:only].empty?
- chg.empty? ? nil : chg
+
+ def prepare_changes(edits)
+ chg = changes.dup
+ chg = chg.delete_if { |key, value| @options[:except].include?(key) } unless @options[:except].empty?
+ chg = chg.delete_if { |key, value| !@options[:only].include?(key) } unless @options[:only].empty?
+ chg.empty? ? nil : chg
+ end
+
+ public
+
+ def self.after_callback(action)
+ define_method("after_#{action}") do |model|
+ audit_after(model, action)
end
-
+ end
+
+ alias :before_create :audit_before
+ alias :before_update :audit_before
+ alias :before_destroy :audit_before
+
+ after_callback(:create)
+ after_callback(:update)
+ after_callback(:destroy)
end
-end
+end
View
8 lib/auditor/spec_helpers.rb
@@ -1,19 +1,19 @@
module Auditor
module SpecHelpers
- include Auditor::Integration
-
+ include Auditor::Status
+
def self.included(base)
base.class_eval do
before(:each) do
disable_auditor
end
-
+
after(:each) do
enable_auditor
end
end
end
-
+
end
end
View
56 lib/auditor/integration.rb → lib/auditor/status.rb
@@ -1,49 +1,47 @@
-require 'auditor/thread_status'
-
module Auditor
- module Integration
-
+ module Status
+
+ def auditor_disabled?
+ Thread.current[:auditor_disabled] == true
+ end
+
+ def auditor_enabled?
+ Thread.current[:auditor_disabled] == false
+ end
+
+ def disable_auditor
+ Thread.current[:auditor_disabled] = true
+ end
+
+ def enable_auditor
+ Thread.current[:auditor_disabled] = false
+ end
+
def without_auditor
previously_disabled = auditor_disabled?
- disable_auditor
-
+
begin
+ disable_auditor
result = yield if block_given?
ensure
enable_auditor unless previously_disabled
end
-
+
result
end
-
+
def with_auditor
previously_disabled = auditor_disabled?
- enable_auditor
-
+
begin
+ enable_auditor
result = yield if block_given?
ensure
disable_auditor if previously_disabled
end
-
+
result
end
-
- def disable_auditor
- Auditor::ThreadStatus.disable
- end
-
- def enable_auditor
- Auditor::ThreadStatus.enable
- end
-
- def auditor_disabled?
- Auditor::ThreadStatus.disabled?
- end
-
- def auditor_enabled?
- Auditor::ThreadStatus.enabled?
- end
-
+
end
-end
+end
View
18 lib/auditor/thread_local.rb
@@ -1,18 +0,0 @@
-module Auditor
- class ThreadLocal
-
- def initialize(initial_value)
- @thread_symbol = "#{rand}#{Time.now.to_f}"
- set initial_value
- end
-
- def set(value)
- Thread.current[@thread_symbol] = value
- end
-
- def get
- Thread.current[@thread_symbol]
- end
-
- end
-end
View
34 lib/auditor/thread_status.rb
@@ -1,34 +0,0 @@
-require 'auditor/thread_local'
-
-module Auditor
- module ThreadStatus
-
- def self.enabled?
- status
- end
-
- def self.disabled?
- !status
- end
-
- def self.enable
- set_status true
- end
-
- def self.disable
- set_status false
- end
-
- private
- def self.status
- @status = Auditor::ThreadLocal.new(true) if @status.nil?
- @status.get
- end
-
- def self.set_status(status)
- @status = Auditor::ThreadLocal.new(true) if @status.nil?
- @status.set status
- end
-
- end
-end
View
11 lib/auditor/user.rb
@@ -1,16 +1,15 @@
module Auditor
module User
+
def current_user
- Thread.current[@@current_user_symbol]
+ Thread.current[:auditor_user]
end
def current_user=(user)
- Thread.current[@@current_user_symbol] = user
+ Thread.current[:auditor_user] = user
end
-
+
module_function :current_user, :current_user=
- private
- @@current_user_symbol = :auditor_current_user
end
-end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.