cia 0.2.3 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cia (0.2.3)
4
+ cia (0.3.0)
5
5
 
6
6
  GEM
7
7
  remote: http://rubygems.org/
@@ -1,15 +1,11 @@
1
- create_table :cia_transactions do |t|
1
+ create_table :cia_events do |t|
2
2
  t.integer :actor_id
3
3
  t.string :actor_type
4
+ t.string :source_type, :action, :null => false
5
+ t.integer :source_id, :null => false
4
6
  t.string :ip_address
5
- t.timestamp :created_at
6
- end
7
-
8
- create_table :cia_events do |t|
9
- t.string :type, :source_type, :null => false
10
- t.integer :cia_transaction_id, :source_id, :null => false
11
7
  t.string :message
12
- t.timestamp :created_at
8
+ t.timestamp :created_at#, :null => false
13
9
  end
14
10
 
15
11
  create_table :cia_attribute_changes do |t|
@@ -19,6 +15,5 @@ create_table :cia_attribute_changes do |t|
19
15
  end
20
16
 
21
17
  # DOWN
22
- # drop_table :cia_transactions
23
18
  # drop_table :cia_events
24
19
  # drop_table :cia_attribute_changes
data/Readme.md CHANGED
@@ -1,19 +1,16 @@
1
1
  Central Internal Auditing
2
2
  ============================
3
3
 
4
- Audit model events like update/create/delete + attribute changes.
4
+ Audit model actions like update/create/destroy/<custom> + attribute changes.
5
5
 
6
- - very normalized and queryable through table layout
6
+ - normalized and queryable through table layout
7
7
  - actors and subjects are polymorphic
8
- - events come in different types like `CIA::UpdateEvent`
9
- - transactions wrap multiple events, a nice place to add debugging info like source/action/ip
10
8
  - works on ActiveRecord 2 and 3
11
9
 
12
10
  Table layout:
13
11
 
14
- 1 Transaction (actor/ip/time/...)
15
- -> has many events (updated subject + message)
16
- -> has many attribute changes (changed password from foo to bar on subject)
12
+ Event (actor/ip/time/updated subject + message)
13
+ -> has many attribute changes (changed password from foo to bar on subject)
17
14
 
18
15
 
19
16
  Install
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: /Users/mgrosser/code/tools/cia
3
3
  specs:
4
- cia (0.2.2)
4
+ cia (0.2.3)
5
5
 
6
6
  GEM
7
7
  remote: http://rubygems.org/
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: /Users/mgrosser/code/tools/cia
3
3
  specs:
4
- cia (0.2.2)
4
+ cia (0.2.3)
5
5
 
6
6
  GEM
7
7
  remote: http://rubygems.org/
data/lib/cia.rb CHANGED
@@ -1,12 +1,7 @@
1
1
  require 'active_record'
2
2
  require 'cia/version'
3
3
  require 'cia/auditable'
4
- require 'cia/null_transaction'
5
- require 'cia/transaction'
6
4
  require 'cia/event'
7
- require 'cia/create_event'
8
- require 'cia/update_event'
9
- require 'cia/delete_event'
10
5
  require 'cia/attribute_change'
11
6
 
12
7
  module CIA
@@ -15,18 +10,31 @@ module CIA
15
10
  end
16
11
 
17
12
  def self.audit(options = {})
18
- Thread.current[:cia_transaction] = Transaction.new(options)
13
+ Thread.current[:cia_transaction] = options
19
14
  yield
20
15
  ensure
21
16
  Thread.current[:cia_transaction] = nil
22
17
  end
23
18
 
24
19
  def self.current_transaction
25
- Thread.current[:cia_transaction] || NullTransaction
20
+ Thread.current[:cia_transaction]
26
21
  end
27
22
 
28
- def self.record_audit(event_type, object)
29
- CIA.current_transaction.record(event_type, object)
23
+ def self.record(action, source)
24
+ return unless current_transaction
25
+
26
+ changes = source.changes.slice(*source.class.audited_attributes)
27
+ message = source.audit_message if source.respond_to?(:audit_message)
28
+
29
+ return if not message and changes.empty? and action.to_s == "update"
30
+
31
+ event = CIA::Event.create!(
32
+ :action => action.to_s,
33
+ :source => source,
34
+ :message => message
35
+ )
36
+ event.record_attribute_changes!(changes)
37
+ event
30
38
  rescue Object => e
31
39
  if exception_handler
32
40
  exception_handler.call e
@@ -3,9 +3,9 @@ module CIA
3
3
  def self.included(base)
4
4
  base.class_attribute :audited_attributes
5
5
  base.send :extend, ClassMethods
6
- base.after_create {|record| CIA.record_audit(CIA::CreateEvent, record) }
7
- base.after_update {|record| CIA.record_audit(CIA::UpdateEvent, record) }
8
- base.after_destroy {|record| CIA.record_audit(CIA::DeleteEvent, record) }
6
+ base.after_create {|record| CIA.record(:create, record) }
7
+ base.after_update {|record| CIA.record(:update, record) }
8
+ base.after_destroy {|record| CIA.record(:destroy, record) }
9
9
  end
10
10
 
11
11
  module ClassMethods
@@ -1,13 +1,12 @@
1
1
  module CIA
2
2
  class Event < ActiveRecord::Base
3
- abstract_class
4
3
  self.table_name = "cia_events"
5
4
 
5
+ belongs_to :actor, :polymorphic => true
6
6
  belongs_to :source, :polymorphic => true
7
- belongs_to :transaction, :foreign_key => :cia_transaction_id
8
7
  has_many :attribute_changes, :foreign_key => :cia_event_id
9
8
 
10
- validates_presence_of :transaction, :source, :type
9
+ validates_presence_of :source, :action
11
10
 
12
11
  def self.previous
13
12
  scoped(:order => "id desc")
@@ -1,3 +1,3 @@
1
1
  module CIA
2
- VERSION = '0.2.3'
2
+ VERSION = '0.3.0'
3
3
  end
@@ -7,20 +7,20 @@ describe CIA do
7
7
 
8
8
  describe ".audit" do
9
9
  it "has no transaction when it starts" do
10
- CIA.current_transaction.should == CIA::NullTransaction
10
+ CIA.current_transaction.should == nil
11
11
  end
12
12
 
13
13
  it "starts a new transaction" do
14
14
  result = 1
15
- CIA.audit({}) do
15
+ CIA.audit({:a => 1}) do
16
16
  result = CIA.current_transaction
17
17
  end
18
- result.class.should == CIA::Transaction
18
+ result.should == {:a => 1}
19
19
  end
20
20
 
21
21
  it "stops the transaction after the block" do
22
22
  CIA.audit({}){}
23
- CIA.current_transaction.should == CIA::NullTransaction
23
+ CIA.current_transaction.should == nil
24
24
  end
25
25
 
26
26
  it "returns the block content" do
@@ -34,14 +34,13 @@ describe CIA do
34
34
  end
35
35
  end
36
36
  sleep 0.01
37
- CIA.current_transaction.should == CIA::NullTransaction
37
+ CIA.current_transaction.should == nil
38
38
  sleep 0.04 # so next tests dont fail
39
39
  end
40
40
  end
41
41
 
42
- describe ".record_audit" do
42
+ describe ".record" do
43
43
  let(:object) { Car.new }
44
- let(:transaction) { CIA.current_transaction }
45
44
 
46
45
  around do |example|
47
46
  CIA.audit :actor => User.create! do
@@ -53,7 +52,7 @@ describe CIA do
53
52
  expect{
54
53
  object.save!
55
54
  }.to change{ CIA::Event.count }.by(+1)
56
- CIA::Event.last.class.should == CIA::CreateEvent
55
+ CIA::Event.last.action.should == "create"
57
56
  end
58
57
 
59
58
  it "tracks delete" do
@@ -61,7 +60,7 @@ describe CIA do
61
60
  expect{
62
61
  object.destroy
63
62
  }.to change{ CIA::Event.count }.by(+1)
64
- CIA::Event.last.class.should == CIA::DeleteEvent
63
+ CIA::Event.last.action.should == "destroy"
65
64
  end
66
65
 
67
66
  it "tracks update" do
@@ -69,13 +68,78 @@ describe CIA do
69
68
  expect{
70
69
  object.update_attributes(:wheels => 3)
71
70
  }.to change{ CIA::Event.count }.by(+1)
72
- CIA::Event.last.class.should == CIA::UpdateEvent
71
+ CIA::Event.last.action.should == "update"
72
+ end
73
+
74
+ context "events" do
75
+ def parse_event_changes(event)
76
+ event.attribute_changes.map { |c| [c.attribute_name, c.old_value, c.new_value] }
77
+ end
78
+
79
+ it "records attribute creations" do
80
+ source = Car.create!
81
+ source.wheels = 4
82
+ event = CIA.record(:update, source)
83
+
84
+ parse_event_changes(event).should == [["wheels", nil, "4"]]
85
+ end
86
+
87
+ it "records multiple attributes" do
88
+ source = CarWith3Attributes.create!
89
+ source.wheels = 4
90
+ source.drivers = 2
91
+ source.color = "red"
92
+ event = CIA.record(:update, source)
93
+
94
+ parse_event_changes(event).should =~ [["wheels", nil, "4"], ["drivers", nil, "2"], ["color", nil, "red"]]
95
+ end
96
+
97
+ it "records attribute changes" do
98
+ source = Car.create!(:wheels => 2)
99
+ source.wheels = 4
100
+ event = CIA.record(:update, source)
101
+ parse_event_changes(event).should == [["wheels", "2", "4"]]
102
+ end
103
+
104
+ it "records attribute deletions" do
105
+ source = Car.create!(:wheels => 2)
106
+ source.wheels = nil
107
+ event = CIA.record(:update, source)
108
+ parse_event_changes(event).should == [["wheels", "2", nil]]
109
+ end
110
+
111
+ it "does not record unaudited attribute changes" do
112
+ source = Car.create!
113
+ source.drivers = 2
114
+ event = nil
115
+ expect{
116
+ event = CIA.record(:update, source)
117
+ }.to_not change{ CIA::Event.count }
118
+
119
+ event.should == nil
120
+ end
121
+
122
+ it "records audit_message as message even if there are no changes" do
123
+ source = CarWithAMessage.create!
124
+ source.audit_message = "Foo"
125
+ event = CIA.record(:update, source)
126
+
127
+ event.message.should == "Foo"
128
+ parse_event_changes(event).should == []
129
+ end
130
+
131
+ it "record non-updates even without changes" do
132
+ source = Car.create!
133
+ event = CIA.record(:create, source)
134
+
135
+ parse_event_changes(event).should == []
136
+ end
73
137
  end
74
138
 
75
139
  context "exception_handler" do
76
140
  before do
77
141
  $stderr.stub(:puts)
78
- transaction.stub(:record).and_raise(StandardError.new("foo"))
142
+ CIA.stub(:current_transaction).and_raise(StandardError.new("foo"))
79
143
  end
80
144
 
81
145
  def capture_exception
@@ -3,7 +3,6 @@ require 'cia'
3
3
 
4
4
  RSpec.configure do |config|
5
5
  config.before do
6
- CIA::Transaction.delete_all
7
6
  CIA::Event.delete_all
8
7
  CIA::AttributeChange.delete_all
9
8
  end
@@ -50,17 +49,8 @@ class CarWith3Attributes < ActiveRecord::Base
50
49
  audit_attribute :drivers
51
50
  end
52
51
 
53
- class CarWithoutObservers < ActiveRecord::Base
54
- self.table_name = "cars"
55
- end
56
-
57
- class CarWithoutObservers2 < ActiveRecord::Base
58
- self.table_name = "cars"
59
- end
60
-
61
52
  def create_event
62
- transaction = CIA::Transaction.create!(:actor => User.create!)
63
- CIA::UpdateEvent.create!(:source => Car.create!, :transaction => transaction)
53
+ CIA::Event.create!(:source => Car.create!, :actor => User.create!, :action => "update")
64
54
  end
65
55
 
66
56
  def create_change(options={})
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cia
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-06-22 00:00:00.000000000 Z
12
+ date: 2012-06-25 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description:
15
15
  email: michael@grosser.it
@@ -32,16 +32,10 @@ files:
32
32
  - lib/cia.rb
33
33
  - lib/cia/attribute_change.rb
34
34
  - lib/cia/auditable.rb
35
- - lib/cia/create_event.rb
36
- - lib/cia/delete_event.rb
37
35
  - lib/cia/event.rb
38
- - lib/cia/null_transaction.rb
39
- - lib/cia/transaction.rb
40
- - lib/cia/update_event.rb
41
36
  - lib/cia/version.rb
42
37
  - spec/cia/attribute_change_spec.rb
43
38
  - spec/cia/event_spec.rb
44
- - spec/cia/transaction_spec.rb
45
39
  - spec/cia_spec.rb
46
40
  - spec/spec_helper.rb
47
41
  homepage: http://github.com/grosser/cia
@@ -59,7 +53,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
59
53
  version: '0'
60
54
  segments:
61
55
  - 0
62
- hash: -3661699799177729927
56
+ hash: -1846204307001126824
63
57
  required_rubygems_version: !ruby/object:Gem::Requirement
64
58
  none: false
65
59
  requirements:
@@ -68,7 +62,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
68
62
  version: '0'
69
63
  segments:
70
64
  - 0
71
- hash: -3661699799177729927
65
+ hash: -1846204307001126824
72
66
  requirements: []
73
67
  rubyforge_project:
74
68
  rubygems_version: 1.8.24
@@ -1,4 +0,0 @@
1
- module CIA
2
- class CreateEvent < Event
3
- end
4
- end
@@ -1,4 +0,0 @@
1
- module CIA
2
- class DeleteEvent < Event
3
- end
4
- end
@@ -1,6 +0,0 @@
1
- module CIA
2
- class NullTransaction
3
- def self.record(*args)
4
- end
5
- end
6
- end
@@ -1,23 +0,0 @@
1
- module CIA
2
- class Transaction < ActiveRecord::Base
3
- self.table_name = "cia_transactions"
4
-
5
- belongs_to :actor, :polymorphic => true
6
- has_many :events, :foreign_key => :cia_transaction_id
7
-
8
- def record(event_type, source)
9
- changes = source.changes.slice(*source.class.audited_attributes)
10
- message = source.audit_message if source.respond_to?(:audit_message)
11
-
12
- return if not message and changes.empty? and event_type == CIA::UpdateEvent
13
-
14
- event = event_type.create!(
15
- :source => source,
16
- :transaction => self,
17
- :message => message
18
- )
19
- event.record_attribute_changes!(changes)
20
- event
21
- end
22
- end
23
- end
@@ -1,4 +0,0 @@
1
- module CIA
2
- class UpdateEvent < Event
3
- end
4
- end
@@ -1,75 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe CIA::Transaction do
4
- it "has many events" do
5
- event = create_event
6
- event.transaction.events.should == [event]
7
- end
8
-
9
- context "#record" do
10
- def parse_event_changes(event)
11
- event.attribute_changes.map { |c| [c.attribute_name, c.old_value, c.new_value] }
12
- end
13
-
14
- let(:transaction){ CIA::Transaction.new(:actor => User.create!) }
15
-
16
- it "records attribute creations" do
17
- source = Car.create!
18
- source.wheels = 4
19
- event = transaction.record(CIA::UpdateEvent, source)
20
-
21
- parse_event_changes(event).should == [["wheels", nil, "4"]]
22
- end
23
-
24
- it "records multiple attributes" do
25
- source = CarWith3Attributes.create!
26
- source.wheels = 4
27
- source.drivers = 2
28
- source.color = "red"
29
- event = transaction.record(CIA::UpdateEvent, source)
30
-
31
- parse_event_changes(event).should =~ [["wheels", nil, "4"], ["drivers", nil, "2"], ["color", nil, "red"]]
32
- end
33
-
34
- it "records attribute changes" do
35
- source = Car.create!(:wheels => 2)
36
- source.wheels = 4
37
- event = transaction.record(CIA::UpdateEvent, source)
38
- parse_event_changes(event).should == [["wheels", "2", "4"]]
39
- end
40
-
41
- it "records attribute deletions" do
42
- source = Car.create!(:wheels => 2)
43
- source.wheels = nil
44
- event = transaction.record(CIA::UpdateEvent, source)
45
- parse_event_changes(event).should == [["wheels", "2", nil]]
46
- end
47
-
48
- it "does not record unaudited attribute changes" do
49
- source = Car.create!
50
- source.drivers = 2
51
- event = nil
52
- expect{
53
- event = transaction.record(CIA::UpdateEvent, source)
54
- }.to_not change{ CIA::Event.count }
55
-
56
- event.should == nil
57
- end
58
-
59
- it "records audit_message as message even if there are no changes" do
60
- source = CarWithAMessage.create!
61
- source.audit_message = "Foo"
62
- event = transaction.record(CIA::UpdateEvent, source)
63
-
64
- event.message.should == "Foo"
65
- parse_event_changes(event).should == []
66
- end
67
-
68
- it "record non-updates even without changes" do
69
- source = Car.create!
70
- event = transaction.record(CIA::CreateEvent, source)
71
-
72
- parse_event_changes(event).should == []
73
- end
74
- end
75
- end