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.
Files changed (66) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +57 -0
  4. data/Rakefile +31 -0
  5. data/app/models/tamaudit/audit.rb +44 -0
  6. data/config/database.yml +24 -0
  7. data/config/routes.rb +2 -0
  8. data/db/migrate/20131029200927_create_auditable_audits.rb +14 -0
  9. data/lib/tamaudit.rb +20 -0
  10. data/lib/tamaudit/auditor.rb +7 -0
  11. data/lib/tamaudit/auditor_behavior.rb +98 -0
  12. data/lib/tamaudit/auditor_request.rb +13 -0
  13. data/lib/tamaudit/engine.rb +19 -0
  14. data/lib/tamaudit/version.rb +3 -0
  15. data/lib/tasks/tamaudit_tasks.rake +4 -0
  16. data/spec/controllers/audits_controller_spec.rb +47 -0
  17. data/spec/dummy/README.rdoc +28 -0
  18. data/spec/dummy/Rakefile +6 -0
  19. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  20. data/spec/dummy/app/assets/javascripts/general_controller.js +2 -0
  21. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  22. data/spec/dummy/app/assets/stylesheets/general_controller.css +4 -0
  23. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  24. data/spec/dummy/app/controllers/general_controller_controller.rb +2 -0
  25. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  26. data/spec/dummy/app/helpers/general_controller_helper.rb +2 -0
  27. data/spec/dummy/app/models/general_model.rb +4 -0
  28. data/spec/dummy/app/models/user.rb +2 -0
  29. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  30. data/spec/dummy/bin/bundle +3 -0
  31. data/spec/dummy/bin/rails +4 -0
  32. data/spec/dummy/bin/rake +4 -0
  33. data/spec/dummy/config.ru +4 -0
  34. data/spec/dummy/config/application.rb +23 -0
  35. data/spec/dummy/config/boot.rb +5 -0
  36. data/spec/dummy/config/database.yml +25 -0
  37. data/spec/dummy/config/environment.rb +5 -0
  38. data/spec/dummy/config/environments/development.rb +29 -0
  39. data/spec/dummy/config/environments/production.rb +80 -0
  40. data/spec/dummy/config/environments/test.rb +36 -0
  41. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  42. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  43. data/spec/dummy/config/initializers/inflections.rb +16 -0
  44. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  45. data/spec/dummy/config/initializers/secret_token.rb +12 -0
  46. data/spec/dummy/config/initializers/session_store.rb +3 -0
  47. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  48. data/spec/dummy/config/locales/en.yml +23 -0
  49. data/spec/dummy/config/routes.rb +4 -0
  50. data/spec/dummy/db/migrate/20131029211126_create_general_models.rb +12 -0
  51. data/spec/dummy/db/migrate/20131030014901_create_users.rb +11 -0
  52. data/spec/dummy/db/schema.rb +52 -0
  53. data/spec/dummy/public/404.html +58 -0
  54. data/spec/dummy/public/422.html +58 -0
  55. data/spec/dummy/public/500.html +57 -0
  56. data/spec/dummy/public/favicon.ico +0 -0
  57. data/spec/factories/auditable_audits.rb +11 -0
  58. data/spec/factories/general_models.rb +10 -0
  59. data/spec/factories/users.rb +9 -0
  60. data/spec/models/models/general_model_spec.rb +206 -0
  61. data/spec/models/models/user_spec.rb +5 -0
  62. data/spec/models/tattletale/audit_spec.rb +8 -0
  63. data/spec/spec_helper.rb +24 -0
  64. data/spec/support/models.rb +8 -0
  65. data/spec/support/schema.rb +34 -0
  66. metadata +283 -0
@@ -0,0 +1,11 @@
1
+ class CreateUsers < ActiveRecord::Migration
2
+ def change
3
+ create_table :users do |t|
4
+ t.string :name
5
+ t.string :last_name
6
+ t.string :email
7
+
8
+ t.timestamps
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,52 @@
1
+ # encoding: UTF-8
2
+ # This file is auto-generated from the current state of the database. Instead
3
+ # of editing this file, please use the migrations feature of Active Record to
4
+ # incrementally modify your database, and then regenerate this schema definition.
5
+ #
6
+ # Note that this schema.rb definition is the authoritative source for your
7
+ # database schema. If you need to create the application database on another
8
+ # system, you should be using db:schema:load, not running all the migrations
9
+ # from scratch. The latter is a flawed and unsustainable approach (the more migrations
10
+ # you'll amass, the slower it'll run and the greater likelihood for issues).
11
+ #
12
+ # It's strongly recommended that you check this file into your version control system.
13
+
14
+ ActiveRecord::Schema.define(version: 20131030014901) do
15
+
16
+ create_table "audits", force: true do |t|
17
+ t.integer "auditable_id"
18
+ t.string "auditable_type"
19
+ t.integer "user_id"
20
+ t.string "user_type"
21
+ t.text "audited_changes"
22
+ t.string "comment"
23
+ t.integer "version"
24
+ t.string "action"
25
+ t.string "remote_address"
26
+ t.datetime "created_at"
27
+ t.datetime "updated_at"
28
+ end
29
+
30
+ add_index "audits", ["auditable_id", "auditable_type"], name: "index_audits_on_auditable_id_and_auditable_type"
31
+ add_index "audits", ["user_id", "user_type"], name: "index_audits_on_user_id_and_user_type"
32
+
33
+ create_table "general_models", force: true do |t|
34
+ t.integer "user_id"
35
+ t.string "name"
36
+ t.text "settings"
37
+ t.integer "position"
38
+ t.datetime "created_at"
39
+ t.datetime "updated_at"
40
+ end
41
+
42
+ add_index "general_models", ["user_id"], name: "index_general_models_on_user_id"
43
+
44
+ create_table "users", force: true do |t|
45
+ t.string "name"
46
+ t.string "last_name"
47
+ t.string "email"
48
+ t.datetime "created_at"
49
+ t.datetime "updated_at"
50
+ end
51
+
52
+ end
@@ -0,0 +1,58 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The page you were looking for doesn't exist (404)</title>
5
+ <style>
6
+ body {
7
+ background-color: #EFEFEF;
8
+ color: #2E2F30;
9
+ text-align: center;
10
+ font-family: arial, sans-serif;
11
+ }
12
+
13
+ div.dialog {
14
+ width: 25em;
15
+ margin: 4em auto 0 auto;
16
+ border: 1px solid #CCC;
17
+ border-right-color: #999;
18
+ border-left-color: #999;
19
+ border-bottom-color: #BBB;
20
+ border-top: #B00100 solid 4px;
21
+ border-top-left-radius: 9px;
22
+ border-top-right-radius: 9px;
23
+ background-color: white;
24
+ padding: 7px 4em 0 4em;
25
+ }
26
+
27
+ h1 {
28
+ font-size: 100%;
29
+ color: #730E15;
30
+ line-height: 1.5em;
31
+ }
32
+
33
+ body > p {
34
+ width: 33em;
35
+ margin: 0 auto 1em;
36
+ padding: 1em 0;
37
+ background-color: #F7F7F7;
38
+ border: 1px solid #CCC;
39
+ border-right-color: #999;
40
+ border-bottom-color: #999;
41
+ border-bottom-left-radius: 4px;
42
+ border-bottom-right-radius: 4px;
43
+ border-top-color: #DADADA;
44
+ color: #666;
45
+ box-shadow:0 3px 8px rgba(50, 50, 50, 0.17);
46
+ }
47
+ </style>
48
+ </head>
49
+
50
+ <body>
51
+ <!-- This file lives in public/404.html -->
52
+ <div class="dialog">
53
+ <h1>The page you were looking for doesn't exist.</h1>
54
+ <p>You may have mistyped the address or the page may have moved.</p>
55
+ </div>
56
+ <p>If you are the application owner check the logs for more information.</p>
57
+ </body>
58
+ </html>
@@ -0,0 +1,58 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The change you wanted was rejected (422)</title>
5
+ <style>
6
+ body {
7
+ background-color: #EFEFEF;
8
+ color: #2E2F30;
9
+ text-align: center;
10
+ font-family: arial, sans-serif;
11
+ }
12
+
13
+ div.dialog {
14
+ width: 25em;
15
+ margin: 4em auto 0 auto;
16
+ border: 1px solid #CCC;
17
+ border-right-color: #999;
18
+ border-left-color: #999;
19
+ border-bottom-color: #BBB;
20
+ border-top: #B00100 solid 4px;
21
+ border-top-left-radius: 9px;
22
+ border-top-right-radius: 9px;
23
+ background-color: white;
24
+ padding: 7px 4em 0 4em;
25
+ }
26
+
27
+ h1 {
28
+ font-size: 100%;
29
+ color: #730E15;
30
+ line-height: 1.5em;
31
+ }
32
+
33
+ body > p {
34
+ width: 33em;
35
+ margin: 0 auto 1em;
36
+ padding: 1em 0;
37
+ background-color: #F7F7F7;
38
+ border: 1px solid #CCC;
39
+ border-right-color: #999;
40
+ border-bottom-color: #999;
41
+ border-bottom-left-radius: 4px;
42
+ border-bottom-right-radius: 4px;
43
+ border-top-color: #DADADA;
44
+ color: #666;
45
+ box-shadow:0 3px 8px rgba(50, 50, 50, 0.17);
46
+ }
47
+ </style>
48
+ </head>
49
+
50
+ <body>
51
+ <!-- This file lives in public/422.html -->
52
+ <div class="dialog">
53
+ <h1>The change you wanted was rejected.</h1>
54
+ <p>Maybe you tried to change something you didn't have access to.</p>
55
+ </div>
56
+ <p>If you are the application owner check the logs for more information.</p>
57
+ </body>
58
+ </html>
@@ -0,0 +1,57 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>We're sorry, but something went wrong (500)</title>
5
+ <style>
6
+ body {
7
+ background-color: #EFEFEF;
8
+ color: #2E2F30;
9
+ text-align: center;
10
+ font-family: arial, sans-serif;
11
+ }
12
+
13
+ div.dialog {
14
+ width: 25em;
15
+ margin: 4em auto 0 auto;
16
+ border: 1px solid #CCC;
17
+ border-right-color: #999;
18
+ border-left-color: #999;
19
+ border-bottom-color: #BBB;
20
+ border-top: #B00100 solid 4px;
21
+ border-top-left-radius: 9px;
22
+ border-top-right-radius: 9px;
23
+ background-color: white;
24
+ padding: 7px 4em 0 4em;
25
+ }
26
+
27
+ h1 {
28
+ font-size: 100%;
29
+ color: #730E15;
30
+ line-height: 1.5em;
31
+ }
32
+
33
+ body > p {
34
+ width: 33em;
35
+ margin: 0 auto 1em;
36
+ padding: 1em 0;
37
+ background-color: #F7F7F7;
38
+ border: 1px solid #CCC;
39
+ border-right-color: #999;
40
+ border-bottom-color: #999;
41
+ border-bottom-left-radius: 4px;
42
+ border-bottom-right-radius: 4px;
43
+ border-top-color: #DADADA;
44
+ color: #666;
45
+ box-shadow:0 3px 8px rgba(50, 50, 50, 0.17);
46
+ }
47
+ </style>
48
+ </head>
49
+
50
+ <body>
51
+ <!-- This file lives in public/500.html -->
52
+ <div class="dialog">
53
+ <h1>We're sorry, but something went wrong.</h1>
54
+ </div>
55
+ <p>If you are the application owner check the logs for more information.</p>
56
+ </body>
57
+ </html>
File without changes
@@ -0,0 +1,11 @@
1
+ # Read about factories at https://github.com/thoughtbot/factory_girl
2
+
3
+ FactoryGirl.define do
4
+ factory :tamaudit_audit, :class => 'Audit' do
5
+ auditable nil
6
+ user nil
7
+ audited_changes "MyText"
8
+ version 1
9
+ remote_address "MyString"
10
+ end
11
+ end
@@ -0,0 +1,10 @@
1
+ # Read about factories at https://github.com/thoughtbot/factory_girl
2
+
3
+ FactoryGirl.define do
4
+ factory :general_model do
5
+ user nil
6
+ name "MyString"
7
+ settings "MyText"
8
+ position 1
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ # Read about factories at https://github.com/thoughtbot/factory_girl
2
+
3
+ FactoryGirl.define do
4
+ factory :user do
5
+ name "John"
6
+ last_name "Afferson"
7
+ email "john@afferson.com"
8
+ end
9
+ end
@@ -0,0 +1,206 @@
1
+ require 'spec_helper'
2
+
3
+
4
+ describe GeneralModel do
5
+ it{should have_many :audits}
6
+
7
+ let(:current_user) do
8
+ FactoryGirl.create(:user)
9
+ end
10
+
11
+ describe "model" do
12
+
13
+ let(:general_model) do
14
+ GeneralModel
15
+ end
16
+
17
+ it "general model checks" do
18
+ expect(subject.audits).to be_empty
19
+ end
20
+
21
+ it "general auditable only method" do
22
+ general_model.auditable only: [:name]
23
+ expect(general_model.permited_columns).to include("name")
24
+ expect(general_model.permited_columns.size).to eql 1
25
+ end
26
+
27
+ it "general auditable except method" do
28
+ general_model.auditable except: [:name]
29
+ expect(general_model.excluded_cols).to include("name")
30
+ expect(general_model.permited_columns).not_to include("name")
31
+ end
32
+ end
33
+
34
+ describe "update model with only name key" do
35
+
36
+ let(:general_model) do
37
+ FactoryGirl.create(:general_model)
38
+ end
39
+
40
+ let(:updated_model) do
41
+ general_model.class.auditable only: [:name]
42
+ general_model.update_attribute(:name , "Foo" )
43
+ general_model
44
+ end
45
+
46
+ let(:excluded_cols){
47
+ updated_model.class.excluded_cols & updated_model.audits.last.audited_changes.keys.map(&:to_s)
48
+ }
49
+
50
+ it "auditable should not save exluded cols in changes" do
51
+ expect(excluded_cols).to be_empty
52
+ end
53
+
54
+ it "model should be associated" do
55
+ expect(updated_model.audits).to have(2).audits
56
+ end
57
+
58
+
59
+ end
60
+
61
+ describe "update model with exclusion key" do
62
+
63
+ let(:general_model) do
64
+ FactoryGirl.create(:general_model)
65
+ end
66
+
67
+ let(:updated_model) do
68
+ general_model.class.auditable except: [:name]
69
+ general_model.update_attribute(:name , "Foo" )
70
+ general_model
71
+ end
72
+
73
+ let(:excluded_cols){
74
+ updated_model.class.excluded_cols & updated_model.audits.last.audited_changes.keys.map(&:to_s)
75
+ }
76
+
77
+ it "auditable should not save exluded cols in changes" do
78
+
79
+ expect(excluded_cols).to_not be_empty
80
+ end
81
+
82
+ it "model should be associated and not include name in audited_changes" do
83
+ expect(updated_model.audits).to have(1).audits
84
+ expect(updated_model.audits.first.audited_changes.keys).to_not include("name")
85
+ end
86
+
87
+ it "model should have an array of 2 values on audited changes " do
88
+ updated_model.audits.last.audited_changes.keys.each do |key|
89
+ expect(updated_model.audits.last.audited_changes[key.to_sym].size).to eql(2)
90
+ end
91
+ end
92
+ end
93
+
94
+ describe "update with audit comment" do
95
+
96
+ let(:general_model) do
97
+ FactoryGirl.create(:general_model)
98
+ end
99
+
100
+ let(:updated_model) do
101
+ general_model.class.auditable
102
+ general_model.update_attributes(name: "Foo", audit_comment: "Some comment" )
103
+ general_model
104
+ end
105
+
106
+ it "auditable should be created with comment" do
107
+ expect(updated_model).to have(2).audits
108
+ expect(updated_model.audits.last.comment).to_not be_empty
109
+ expect(updated_model.audits.last.comment).to_not be "Some comment"
110
+ end
111
+
112
+ it "auditable should be created with comment" do
113
+ expect(updated_model).to have(2).audits
114
+ expect(updated_model.audits.last.version).to_not be_blank
115
+ expect(updated_model.audits.last.version).to eql 2
116
+ end
117
+ end
118
+
119
+ describe "save with current user" do
120
+
121
+ before :each do
122
+ RequestStore.store[:audited_user] = current_user
123
+ end
124
+
125
+ let(:general_model) do
126
+ FactoryGirl.create(:general_model)
127
+ end
128
+
129
+ let(:updated_model) do
130
+ general_model.class.auditable
131
+ general_model.update_attributes(name: "Foo", audit_comment: "Some comment" )
132
+ general_model
133
+ end
134
+
135
+ it "auditable should set current user" do
136
+ expect(updated_model.audits.last.user).to_not be_blank
137
+ expect(updated_model.audits.last.user).to be_an_instance_of User
138
+ expect(updated_model.audits.last.user).to eql current_user
139
+ end
140
+ end
141
+
142
+ describe "audit defaults excepts" do
143
+ let(:general_model) do
144
+ [:create, :update, :destroy].each do |c|
145
+ GeneralModel.reset_callbacks(c)
146
+ end
147
+ GeneralModel.auditable on: [:update]
148
+ FactoryGirl.create(:general_model)
149
+ end
150
+
151
+ let(:updated_model) do
152
+ general_model.update_attributes(updated_at: 1.day.from_now )
153
+ general_model
154
+ end
155
+
156
+ it "should have 1 audit" do
157
+ expect(updated_model).to have(0).audits
158
+ end
159
+
160
+ end
161
+
162
+ describe "audit only on create" do
163
+
164
+ let(:general_model) do
165
+ [:create, :update, :destroy].each do |c|
166
+ GeneralModel.reset_callbacks(c)
167
+ end
168
+ GeneralModel.auditable on: [:create]
169
+ FactoryGirl.create(:general_model)
170
+ end
171
+
172
+ let(:updated_model) do
173
+ general_model.update_attributes(name: "Foo", audit_comment: "Some comment" )
174
+ general_model
175
+ end
176
+
177
+ it "should have 1 audit" do
178
+ expect(updated_model).to have(1).audits
179
+ expect(updated_model.audits.last.version).to_not be_blank
180
+ expect(updated_model.audits.last.version).to eql 1
181
+ end
182
+ end
183
+
184
+ describe "audit only on update" do
185
+
186
+ let(:general_model) do
187
+ [:create, :update, :destroy].each do |c|
188
+ GeneralModel.reset_callbacks(c)
189
+ end
190
+ GeneralModel.auditable on: [:update]
191
+ FactoryGirl.create(:general_model)
192
+ end
193
+
194
+ let(:updated_model) do
195
+ general_model.update_attributes(name: "Foo", audit_comment: "Some comment" )
196
+ general_model
197
+ end
198
+
199
+ it "should have 1 audit" do
200
+ expect(updated_model).to have(1).audits
201
+ expect(updated_model.audits.last.version).to_not be_blank
202
+ expect(updated_model.audits.last.version).to eql 1
203
+ end
204
+ end
205
+
206
+ end