access_logging 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2011 Nick Ragaz
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,49 @@
1
+ AccessLogging
2
+ ============
3
+
4
+ Log access to models through your controllers.
5
+
6
+ Requires Rails ~> 3 and Ruby 1.9.2.
7
+
8
+ Usage
9
+ -----
10
+
11
+ create_table "access_logs" do |t|
12
+ t.integer "user_id"
13
+ t.string "user_type", :limit => 16
14
+ t.string "user_email", :limit => 100
15
+ t.string "ip", :limit => 15
16
+ t.datetime "created_at"
17
+ t.datetime "updated_at"
18
+ t.string "user_name", :limit => 48
19
+ t.string "path", :limit => 100
20
+ t.string "model_type", :limit => 24
21
+ t.integer "model_id"
22
+ t.string "description", :default => ""
23
+ t.string "verb", :limit => 24
24
+ end
25
+
26
+ rails generate access_logging:model
27
+
28
+ class SecretsController < ApplicationController
29
+ log_access_to :secret
30
+
31
+ # restful actions: index, show, create, etc.
32
+ end
33
+
34
+ PUT '/sessions/new' # => John Smith signs in
35
+
36
+ GET '/secrets' # => AccessLog.count += 1; John Smith viewed /secrets
37
+ GET '/secrets/1' # => AccessLog.count += 1; John Smith viewed /secrets/1
38
+ PUT '/secrets/1' # => AccessLog.count += 1; John Smith updated /secrets/1
39
+
40
+ etc.
41
+
42
+ AccessLog.find(2).secret # => <Secret id: 1>
43
+
44
+
45
+ TODO
46
+ ----
47
+
48
+ * Add generator
49
+ * Log accesses to Redis first, then dump them into the SQL database later.
data/Rakefile ADDED
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'AccessLogging'
18
+ rdoc.options << '--line-numbers' << '--inline-source'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+
24
+ require 'rake/testtask'
25
+
26
+ Rake::TestTask.new(:test) do |t|
27
+ t.libs << 'lib'
28
+ t.libs << 'test'
29
+ t.pattern = 'test/**/*_test.rb'
30
+ t.verbose = false
31
+ end
32
+
33
+
34
+ task :default => :test
@@ -0,0 +1,51 @@
1
+ require 'active_support/concern'
2
+
3
+ module AccessLogging::Controller
4
+ extend ActiveSupport::Concern
5
+
6
+ module ClassMethods
7
+
8
+ # example usage:
9
+ #
10
+ # class ReportsController < ActionController::Base
11
+ # log_access_to :report, through: :print
12
+ #
13
+ # # restful actions here...
14
+ #
15
+ # def print
16
+ # @report = Report.find(params[:id])
17
+ # end
18
+ # end
19
+ #
20
+ # Also depends on the presence of a `current_anyone` method (probably on
21
+ # ApplicationController) to determine the user.
22
+ def log_access_to(model, opts={})
23
+ after_filter(only: :index) do
24
+ log_access
25
+ end
26
+
27
+ after_filter only: [:show, :create, :edit, :update, :destroy] do
28
+ log_access instance_variable_get("@#{model}")
29
+ end
30
+
31
+ if opts[:through]
32
+ opts[:through] = [ *opts[:through] ]
33
+ opts[:through].each do |action|
34
+ after_filter only: action do
35
+ log_access instance_variable_get("@#{model}"), "#{action}ed"
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ # An alternative to a controller-wide filter (above) -- call something like
43
+ # `log_access(@report, 'transmogrifying')` anywhere in an action.
44
+ def log_access(object=nil, verb=nil)
45
+ return unless current_anyone
46
+ AccessLog.log_request current_anyone, request, model: object, verb: verb
47
+ rescue => e
48
+ # in production, don't kill the request just because logging failed
49
+ raise e if Rails.env.development?
50
+ end
51
+ end
@@ -0,0 +1,97 @@
1
+ require 'active_support/concern'
2
+
3
+ module AccessLogging::Model
4
+ extend ActiveSupport::Concern
5
+
6
+ include DateRangeScopes
7
+
8
+ REDIS_ATTRIBUTES = [
9
+ :created_at,
10
+ :ip, :user_type, :user_id,
11
+ :verb, :model_type, :model_id, :description,
12
+ :path
13
+ ]
14
+
15
+ REDIS_SEPARATOR = "||"
16
+
17
+ included do
18
+ belongs_to :user, polymorphic: true
19
+ belongs_to :model, polymorphic: true
20
+
21
+ before_validation :set_user_name_and_email, :set_description
22
+
23
+ validates_presence_of :ip, :path, :verb,
24
+ :user_name, :user_email, :user_id, :user_type,
25
+ :created_at
26
+
27
+ default_scope order('access_logs.created_at DESC')
28
+ end
29
+
30
+ module ClassMethods
31
+ def log_request(user, request, opts={})
32
+ log = AccessLog.new
33
+ log.user = user
34
+ log.path = request.fullpath
35
+ log.ip = request.remote_ip
36
+
37
+ log.model = opts[:model]
38
+ log.verb = opts[:verb] || default_verb_for_method(request.request_method)
39
+
40
+ return if log.model && log.model.new_record?
41
+
42
+ log.save!
43
+ end
44
+
45
+ def default_verb_for_method(method)
46
+ case method.to_s.upcase
47
+ when 'GET'
48
+ "viewed"
49
+ when 'POST'
50
+ "created"
51
+ when 'PUT'
52
+ "updated"
53
+ when 'DELETE'
54
+ "deleted"
55
+ end
56
+ end
57
+
58
+ def build_from_redis_string(str)
59
+ log = AccessLog.new
60
+ parts = str.split(REDIS_SEPARATOR, -1)
61
+
62
+ REDIS_ATTRIBUTES.each_with_index do |attribute, i|
63
+ log.send "#{attribute}=", parts[i]
64
+ end
65
+
66
+ log
67
+ end
68
+ end
69
+
70
+ def created_at
71
+ self[:created_at] ||= Time.zone.now
72
+ end
73
+
74
+ def redis_string
75
+ REDIS_ATTRIBUTES.map { |attribute| send(attribute) }.join(REDIS_SEPARATOR)
76
+ end
77
+
78
+
79
+ private
80
+
81
+ def set_description
82
+ self.description = "" and return unless model && !model.new_record?
83
+
84
+ if model.respond_to?(:description)
85
+ self.description = model.description
86
+ elsif model.respond_to?(:name)
87
+ self.description = "#{model.class.name} #{model.try(:name)}"
88
+ else
89
+ self.description = "#{model.class.name} #{model.id}"
90
+ end
91
+ end
92
+
93
+ def set_user_name_and_email
94
+ self.user_name = user.try :name
95
+ self.user_email = user.try :email
96
+ end
97
+ end
@@ -0,0 +1,10 @@
1
+ require 'active_support/dependencies'
2
+
3
+ ActiveSupport.on_load(:action_controller) do
4
+ include AccessLogging::Controller
5
+ end
6
+
7
+ module AccessLogging
8
+ autoload :Controller, 'access_logging/controller'
9
+ autoload :Model, 'access_logging/model'
10
+ end
metadata ADDED
@@ -0,0 +1,85 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: access_logging
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Nick Ragaz
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-06-29 00:00:00.000000000 -04:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rails
17
+ requirement: &2157446640 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ~>
21
+ - !ruby/object:Gem::Version
22
+ version: '3'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: *2157446640
26
+ - !ruby/object:Gem::Dependency
27
+ name: date_range_scopes
28
+ requirement: &2157446240 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: *2157446240
37
+ - !ruby/object:Gem::Dependency
38
+ name: sqlite3
39
+ requirement: &2157445780 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ type: :development
46
+ prerelease: false
47
+ version_requirements: *2157445780
48
+ description: Log access to models through your controllers.
49
+ email: nick.ragaz@gmail.com
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files: []
53
+ files:
54
+ - lib/access_logging/controller.rb
55
+ - lib/access_logging/model.rb
56
+ - lib/access_logging.rb
57
+ - MIT-LICENSE
58
+ - Rakefile
59
+ - README.md
60
+ has_rdoc: true
61
+ homepage: http://github.com/nragaz/access_logging
62
+ licenses: []
63
+ post_install_message:
64
+ rdoc_options: []
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ! '>='
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ requirements: []
80
+ rubyforge_project:
81
+ rubygems_version: 1.6.2
82
+ signing_key:
83
+ specification_version: 3
84
+ summary: Log access to models through your controllers.
85
+ test_files: []