the_audit 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/README.md +172 -6
- data/app/assets/javascripts/the_audit.js.coffee +23 -0
- data/app/controllers/_templates_/audits_controller.rb +3 -0
- data/app/controllers/concerns/controller.rb +48 -0
- data/app/helpers/the_audit_helper.rb +26 -0
- data/app/models/_templates_/audit.rb +3 -0
- data/app/models/concerns/base.rb +132 -0
- data/app/views/audits/_form.html.haml +79 -0
- data/app/views/audits/edit.html.haml +6 -0
- data/app/views/audits/index.html.haml +119 -0
- data/app/views/audits/show.html.haml +73 -0
- data/config/locales/en.yml +7 -0
- data/config/locales/ru.yml +7 -0
- data/config/routes.rb +9 -0
- data/db/migrate/20130130163149_create_audits.rb +4 -1
- data/gem_version.rb +3 -0
- data/lib/generators/the_audit/USAGE +29 -0
- data/lib/generators/the_audit/the_audit_generator.rb +38 -0
- data/lib/tasks/bots.rake +24 -0
- data/lib/the_audit.rb +20 -2
- data/lib/the_audit/version.rb +1 -3
- data/pic.png +0 -0
- data/the_audit.gemspec +3 -0
- metadata +55 -13
- data/app/models/audit.rb +0 -24
- data/lib/the_audit/engine.rb +0 -10
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 2675cbddec68c11daf30a5a64d9b50fce3929b5d
|
4
|
+
data.tar.gz: bed7b04919327366a9da14728f5ead1cf627f630
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c01d9037b95c209176380f43dc9ac56e50f193f379153975e310774db8ae828aef22c5c1c3a7030b40eaa53a97f68fadd534b0cc14157ade3b6a77ecab469008
|
7
|
+
data.tar.gz: bc48eda5bf8ef0ee65efb2fefb76e82333ecd20ee329c445016e44c6cc3899ac26c2bc0bcec429ab5c69a3bb04c26d2b4941f927a259ce0dd45c81f956f55fdf
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -1,8 +1,174 @@
|
|
1
|
-
# TheAudit
|
1
|
+
# TheAudit - collect user's request info
|
2
2
|
|
3
|
-
|
4
|
-
#
|
3
|
+
### Простой, расширяемый
|
4
|
+
[#TODO clarify this sentence]
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
TheAudit - делает очень простую вещь - логгирует все базовые данные входящих запросов от пользователя и сохраняет эти данные в БД приложения. Предполагается использовать эти данные для мониторинга входящих запросов в приложение и в каждый отдельный контроллер/действие.
|
7
|
+
|
8
|
+
Work with Rails 4. This gem collects the following fields:
|
9
|
+
User, Obj, Controller/Action, IP,
|
10
|
+
Fullpath, Referer, User agent,
|
11
|
+
Remote addr, Data.
|
12
|
+
[#TODO] clarify this fields and check in Rails 3 version
|
13
|
+
|
14
|
+
Администратор может просматривать все записи аудита, а так-же редактировать и удалять их. По ссылкам можно переходить на конкретные страницы просмотренные пользователем.
|
15
|
+
|
16
|
+
## GUI
|
17
|
+
<table>
|
18
|
+
<tr>
|
19
|
+
<td>TheAudit management web interface => localhost:3000/admin/audits</td>
|
20
|
+
</tr>
|
21
|
+
<tr>
|
22
|
+
<td><img src="https://github.com/the-teacher/the_audit/raw/master/pic.png" alt="TheAudit"></td>
|
23
|
+
</tr>
|
24
|
+
</table>
|
25
|
+
|
26
|
+
## Install
|
27
|
+
**Gemfile**
|
28
|
+
```ruby
|
29
|
+
gem "the_audit"
|
30
|
+
|
31
|
+
# You can use any Bootstrap 3 version (CSS, LESS, SCSS)
|
32
|
+
gem 'bootstrap-sass', github: 'thomas-mcdonald/bootstrap-sass'
|
33
|
+
```
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
bundle
|
37
|
+
```
|
38
|
+
**Generators**
|
39
|
+
|
40
|
+
Show generator note
|
41
|
+
```
|
42
|
+
rails g the_audit --help
|
43
|
+
```
|
44
|
+
|
45
|
+
Run main generator
|
46
|
+
```
|
47
|
+
rails g the_audit install
|
48
|
+
```
|
49
|
+
|
50
|
+
This will create:
|
51
|
+
<pre>
|
52
|
+
app/controllers/admin/audits_controller.rb
|
53
|
+
app/models/audit.rb
|
54
|
+
</pre>
|
55
|
+
|
56
|
+
install TheAudit migration
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
rake the_audit_engine:install:migrations
|
60
|
+
```
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
rake db:migrate
|
64
|
+
```
|
65
|
+
|
66
|
+
|
67
|
+
|
68
|
+
Generated classes:
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
class Admin::AuditsController < ApplicationController
|
72
|
+
include TheAudit::Controller
|
73
|
+
end
|
74
|
+
```
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
class Audit < ActiveRecord::Base
|
78
|
+
include TheAudit::Base
|
79
|
+
end
|
80
|
+
```
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
class CreateAudits < ActiveRecord::Migration
|
84
|
+
def change
|
85
|
+
create_table :audits do |t|
|
86
|
+
t.integer :user_id
|
87
|
+
|
88
|
+
t.string :obj_id
|
89
|
+
t.string :obj_type
|
90
|
+
|
91
|
+
t.string :controller_name
|
92
|
+
t.string :action_name
|
93
|
+
|
94
|
+
t.string :ip
|
95
|
+
t.string :remote_ip
|
96
|
+
t.string :fullpath
|
97
|
+
t.string :referer
|
98
|
+
t.string :user_agent
|
99
|
+
t.string :remote_addr
|
100
|
+
t.string :remote_host
|
101
|
+
|
102
|
+
t.text :data
|
103
|
+
|
104
|
+
# add_index :the_audits, :referer
|
105
|
+
# add_index :the_audits, :user_agent
|
106
|
+
# add_index :the_audits, [:controller_name, :action_name]
|
107
|
+
|
108
|
+
t.timestamps
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
```
|
113
|
+
|
114
|
+
## Integration
|
115
|
+
|
116
|
+
#### Change controllers
|
117
|
+
|
118
|
+
Add to
|
119
|
+
|
120
|
+
**ApplicationController**
|
121
|
+
```ruby
|
122
|
+
class ApplicationController < ActionController::Base
|
123
|
+
after_action :save_audit
|
124
|
+
|
125
|
+
private
|
126
|
+
def save_audit
|
127
|
+
(@audit || Audit.new.init(self)).save unless controller_name == 'audits'
|
128
|
+
end
|
129
|
+
end
|
130
|
+
```
|
131
|
+
|
132
|
+
**any audited controllers**
|
133
|
+
```ruby
|
134
|
+
class UsersController < ApplicationController
|
135
|
+
...
|
136
|
+
before_action :set_audit, only: %w[create show update edit destroy]
|
137
|
+
|
138
|
+
def set_audit
|
139
|
+
@audit = Audit.new.init(self, @user)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
```
|
143
|
+
|
144
|
+
#### GUI
|
145
|
+
|
146
|
+
Assets and Bootstrap
|
147
|
+
|
148
|
+
**application.css**
|
149
|
+
|
150
|
+
```
|
151
|
+
//= require bootstrap
|
152
|
+
```
|
153
|
+
|
154
|
+
**application.js**
|
155
|
+
|
156
|
+
```
|
157
|
+
//= require jquery
|
158
|
+
//= require jquery_ujs
|
159
|
+
|
160
|
+
//= require bootstrap
|
161
|
+
```
|
162
|
+
|
163
|
+
Change your layout
|
164
|
+
|
165
|
+
```ruby
|
166
|
+
= yield :the_audit_main
|
167
|
+
```
|
168
|
+
|
169
|
+
## Use
|
170
|
+
|
171
|
+
http://localhost:3000/admin/audits
|
172
|
+
|
173
|
+
## Locales
|
174
|
+
en, ru
|
@@ -0,0 +1,23 @@
|
|
1
|
+
@TheAudit = do ->
|
2
|
+
init: ->
|
3
|
+
do @init_controller_action_select
|
4
|
+
do @init_datapickers
|
5
|
+
|
6
|
+
init_datapickers: ->
|
7
|
+
now = new Date
|
8
|
+
plus_12 = new Date now.getFullYear(), (now.getMonth()+12), now.getDate()
|
9
|
+
minus_12 = new Date now.getFullYear(), (now.getMonth()-12), now.getDate()
|
10
|
+
|
11
|
+
$("[data-role='date_start'], [data-role='date_end']").datepicker
|
12
|
+
minDate: minus_12,
|
13
|
+
maxDate: plus_12
|
14
|
+
dateFormat: 'yy-mm-dd'
|
15
|
+
|
16
|
+
init_controller_action_select: ->
|
17
|
+
$('@ctrl_acts select').on 'change', (e) ->
|
18
|
+
select = $ e.target
|
19
|
+
value = select.val()
|
20
|
+
|
21
|
+
path = '?'
|
22
|
+
path = "?controller_action=#{ $(e.target).val() }" if value.length
|
23
|
+
location.href path
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module TheAudit
|
2
|
+
module Controller
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
before_action :set_audit, only: %w[ show edit update destroy ]
|
7
|
+
end
|
8
|
+
|
9
|
+
def index
|
10
|
+
@ctrl_acts = Audit
|
11
|
+
.audit_scope(params)
|
12
|
+
.select('DISTINCT controller_name, action_name, COUNT(*) as count')
|
13
|
+
.group('controller_name, action_name')
|
14
|
+
.reorder('count DESC').to_a
|
15
|
+
|
16
|
+
@audits_count = Audit.audit_scope(params).count
|
17
|
+
@audits = Audit.audit_scope(params).pagination(params)
|
18
|
+
end
|
19
|
+
|
20
|
+
def show; end
|
21
|
+
|
22
|
+
def edit; end
|
23
|
+
|
24
|
+
def update
|
25
|
+
if @audit.update(audit_params)
|
26
|
+
redirect_to audit_path(@audit), notice: 'Audit was successfully updated.'
|
27
|
+
else
|
28
|
+
render action: 'edit'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def destroy
|
33
|
+
@audit.destroy
|
34
|
+
redirect_to audits_url
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
# Use callbacks to share common setup or constraints between actions.
|
39
|
+
def set_audit
|
40
|
+
@audit = Audit.find(params[:id])
|
41
|
+
end
|
42
|
+
|
43
|
+
# Never trust parameters from the scary internet, only allow the white list through.
|
44
|
+
def audit_params
|
45
|
+
params.require(:audit).permit(:user_id, :obj_id, :obj_type, :controller_name, :action_name, :ip, :remote_ip, :fullpath, :referer, :user_agent, :remote_addr, :remote_host, :data)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module TheAuditHelper
|
2
|
+
def bot_marker agent
|
3
|
+
return nil unless TheAudit.is_bot?(agent)
|
4
|
+
|
5
|
+
name = case agent
|
6
|
+
when /yandex/mix
|
7
|
+
:Yandex
|
8
|
+
when /google/mix
|
9
|
+
:Google
|
10
|
+
when /ahrefs/mix
|
11
|
+
:Arefs
|
12
|
+
when /exabot/mix
|
13
|
+
:Exa
|
14
|
+
when /interfax/mix
|
15
|
+
:Interfax
|
16
|
+
when /bing/mix
|
17
|
+
:Bing
|
18
|
+
when /riddler/mix
|
19
|
+
:Riddler
|
20
|
+
else
|
21
|
+
:Bot
|
22
|
+
end
|
23
|
+
|
24
|
+
content_tag :span, name, class: 'btn btn-warning btn-xs'
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
module TheAudit
|
2
|
+
module Base
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
include ThePagination::Concern
|
7
|
+
|
8
|
+
belongs_to :user
|
9
|
+
belongs_to :obj, polymorphic: true
|
10
|
+
|
11
|
+
include BaseSorts
|
12
|
+
|
13
|
+
scope :audit_scope, ->(params){
|
14
|
+
by_ip(params)
|
15
|
+
.by_holder(params)
|
16
|
+
.by_referer(params)
|
17
|
+
.by_user_id(params)
|
18
|
+
.by_date_range(params)
|
19
|
+
.by_user_agent(params)
|
20
|
+
.by_controller_action(params)
|
21
|
+
.simple_sort(params)
|
22
|
+
}
|
23
|
+
|
24
|
+
scope :by_user_id, ->(params){
|
25
|
+
uid = params[:user_id]
|
26
|
+
return nil if uid.blank?
|
27
|
+
where(user_id: uid)
|
28
|
+
}
|
29
|
+
|
30
|
+
scope :by_referer, ->(params){
|
31
|
+
referer = params[:referer]
|
32
|
+
return nil if referer.blank?
|
33
|
+
where(referer: referer)
|
34
|
+
}
|
35
|
+
|
36
|
+
scope :by_ip, ->(params){
|
37
|
+
ip = params[:ip]
|
38
|
+
return nil if ip.blank?
|
39
|
+
where(ip: ip)
|
40
|
+
}
|
41
|
+
|
42
|
+
scope :by_user_agent, ->(params){
|
43
|
+
ua = params[:user_agent]
|
44
|
+
return nil if ua.blank?
|
45
|
+
where(user_agent: ua)
|
46
|
+
}
|
47
|
+
|
48
|
+
scope :by_holder, ->(params){
|
49
|
+
return nil if params[:obj_id].blank? && params[:obj_type].blank?
|
50
|
+
_type, id = params[:obj_type], params[:obj_id]
|
51
|
+
|
52
|
+
return where(obj_type: _type) if id.blank?
|
53
|
+
return where(obj_id: id) if _type.blank?
|
54
|
+
|
55
|
+
where(obj_type: _type).where(obj_id: id)
|
56
|
+
}
|
57
|
+
|
58
|
+
scope :by_date_range, ->(params){
|
59
|
+
from, to = params[:date_start], params[:date_end]
|
60
|
+
return nil if from.blank? && to.blank?
|
61
|
+
return where("audits.created_at > ?", from.to_datetime) if to.blank?
|
62
|
+
return where("audits.created_at < ?", to.to_datetime) if from.blank?
|
63
|
+
return where("audits.created_at > ? AND audits.created_at < ?", from.to_datetime, to.to_datetime)
|
64
|
+
}
|
65
|
+
|
66
|
+
scope :by_controller_action, ->(params){
|
67
|
+
ca = params[:controller_action]
|
68
|
+
return nil if ca.blank?
|
69
|
+
|
70
|
+
ctrl, act = ca.split '-'
|
71
|
+
return nil if act.blank?
|
72
|
+
|
73
|
+
where(controller_name: ctrl).where(action_name: act)
|
74
|
+
}
|
75
|
+
|
76
|
+
scope :with_users, ->{ includes(:user) }
|
77
|
+
end
|
78
|
+
|
79
|
+
def user_name
|
80
|
+
user.try(:email) || user.try(:login) || user.try(:username)
|
81
|
+
end
|
82
|
+
|
83
|
+
def user_path context
|
84
|
+
"/users/#{ user.to_param }"
|
85
|
+
end
|
86
|
+
|
87
|
+
def user_id_builder controller
|
88
|
+
controller.try(:current_user).try(:id)
|
89
|
+
end
|
90
|
+
|
91
|
+
def unescape str
|
92
|
+
return nil if str.blank?
|
93
|
+
res_str = CGI::unescape str
|
94
|
+
|
95
|
+
# try to catch:
|
96
|
+
# invalid byte sequence in UTF-8
|
97
|
+
# for search requests form old IE6-8 with cp-1251
|
98
|
+
begin
|
99
|
+
res_str =~ //
|
100
|
+
rescue ArgumentError
|
101
|
+
res_str = CGI.unescape(str).force_encoding('windows-1251').encode
|
102
|
+
end
|
103
|
+
|
104
|
+
res_str
|
105
|
+
end
|
106
|
+
|
107
|
+
def init controller, object = nil, data = {}
|
108
|
+
self.user_id = self.user_id_builder(controller)
|
109
|
+
|
110
|
+
self.obj = object
|
111
|
+
self.action_name = controller.action_name
|
112
|
+
self.controller_name = controller.controller_name
|
113
|
+
|
114
|
+
self.data = data.to_json unless data.blank?
|
115
|
+
|
116
|
+
if r = controller.request
|
117
|
+
self.ip = r.ip
|
118
|
+
self.user_agent = r.user_agent
|
119
|
+
self.bot = TheAudit.is_bot?(r.user_agent)
|
120
|
+
|
121
|
+
self.remote_ip = r.remote_ip
|
122
|
+
self.remote_addr = r.remote_addr
|
123
|
+
self.remote_host = r.remote_host
|
124
|
+
|
125
|
+
self.fullpath = self.unescape(r.fullpath) || ''
|
126
|
+
self.referer = self.unescape(r.referer) || :direct_visit
|
127
|
+
end
|
128
|
+
|
129
|
+
self
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
= form_for([:admin, @audit]) do |f|
|
2
|
+
-if @audit.errors.any?
|
3
|
+
#error_explanation
|
4
|
+
%h2= "#{pluralize(@audit.errors.count, "error")} prohibited this audit from being saved:"
|
5
|
+
%ul
|
6
|
+
- @audit.errors.full_messages.each do |msg|
|
7
|
+
.alert.alert-danger
|
8
|
+
%li= msg
|
9
|
+
%table.table.table-striped.table-hover
|
10
|
+
%tr
|
11
|
+
%td
|
12
|
+
/ #TODO Place the button to better place
|
13
|
+
= f.submit t('the_audit.save'), class: 'btn btn-info'
|
14
|
+
%td
|
15
|
+
%tr
|
16
|
+
%td
|
17
|
+
=f.label :user_id
|
18
|
+
%td
|
19
|
+
=f.label "#{@audit.user_id.nil? ? 'Guest' : @audit.user_id}", class: 'form-control'
|
20
|
+
%tr
|
21
|
+
%td
|
22
|
+
=f.label :obj_id
|
23
|
+
%td
|
24
|
+
=f.text_field :obj_id, class: 'form-control'
|
25
|
+
%tr
|
26
|
+
%td
|
27
|
+
=f.label :obj_type
|
28
|
+
%td
|
29
|
+
=f.text_field :obj_type, class: 'form-control'
|
30
|
+
%tr
|
31
|
+
%td
|
32
|
+
=f.label :controller_name
|
33
|
+
%td
|
34
|
+
=f.text_field :controller_name, class: 'form-control'
|
35
|
+
%tr
|
36
|
+
%td
|
37
|
+
=f.label :action_name
|
38
|
+
%td
|
39
|
+
=f.text_field :action_name, class: 'form-control'
|
40
|
+
%tr
|
41
|
+
%td
|
42
|
+
=f.label :ip, 'IP'
|
43
|
+
%td
|
44
|
+
=f.text_field :ip, class: 'form-control'
|
45
|
+
%tr
|
46
|
+
%td
|
47
|
+
=f.label :remote_ip, 'Remote IP'
|
48
|
+
%td
|
49
|
+
=f.text_field :remote_ip, class: 'form-control'
|
50
|
+
%tr
|
51
|
+
%td
|
52
|
+
=f.label :fullpath
|
53
|
+
%td
|
54
|
+
=f.text_field :fullpath, class: 'form-control'
|
55
|
+
%tr
|
56
|
+
%td
|
57
|
+
=f.label :referer
|
58
|
+
%td
|
59
|
+
=f.text_field :referer, class: 'form-control'
|
60
|
+
%tr
|
61
|
+
%td
|
62
|
+
=f.label :user_agent
|
63
|
+
%td
|
64
|
+
=f.text_field :user_agent, class: 'form-control'
|
65
|
+
%tr
|
66
|
+
%td
|
67
|
+
=f.label :remote_addr
|
68
|
+
%td
|
69
|
+
=f.text_field :remote_addr, class: 'form-control'
|
70
|
+
%tr
|
71
|
+
%td
|
72
|
+
=f.label :remote_host
|
73
|
+
%td
|
74
|
+
=f.text_field :remote_host, class: 'form-control'
|
75
|
+
%tr
|
76
|
+
%td
|
77
|
+
=f.label :data
|
78
|
+
%td
|
79
|
+
=f.text_area :data, class: 'form-control'
|
@@ -0,0 +1,119 @@
|
|
1
|
+
- content_for :the_audit_main do
|
2
|
+
%h1= t('the_audit.list_title')
|
3
|
+
|
4
|
+
.alert.alert-warning
|
5
|
+
%p Данная страница позволяет наблюдать за заходами на различные страницы сайта.
|
6
|
+
%p Здесь можно проследить IP адрес посетителя, название его браузера и некоторую другую информацию.
|
7
|
+
|
8
|
+
.alert.alert-info
|
9
|
+
%p Основная задача сбора этой информации - отслеживание заходов Поисковых ботов на конкретную страницу.
|
10
|
+
|
11
|
+
%p
|
12
|
+
Записей: #{ @audits_count }
|
13
|
+
|
14
|
+
= paginate @audits
|
15
|
+
|
16
|
+
.panel.panel-success
|
17
|
+
.panel-heading
|
18
|
+
Фильтры
|
19
|
+
= form_tag '', method: :get, role: :form do
|
20
|
+
.panel-body
|
21
|
+
.form-group
|
22
|
+
.row
|
23
|
+
.col-xs-4
|
24
|
+
%label{ for: :user_id }
|
25
|
+
user_id
|
26
|
+
= link_to "X", params.except(:user_id)
|
27
|
+
= text_field_tag :user_id, params[:user_id], placeholder: "user_id", class: 'form-control'
|
28
|
+
.col-xs-4
|
29
|
+
%label{ for: :ip }
|
30
|
+
IP адрес
|
31
|
+
= link_to "X", params.except(:ip)
|
32
|
+
= text_field_tag :ip, params[:ip], placeholder: "IP адрес", class: 'form-control'
|
33
|
+
.col-xs-4
|
34
|
+
%label{ for: :user_agent }
|
35
|
+
User Agent
|
36
|
+
= link_to "X", params.except(:user_agent)
|
37
|
+
= text_field_tag :user_agent, params[:user_agent], placeholder: "User agent", class: 'form-control'
|
38
|
+
.form-group
|
39
|
+
.row
|
40
|
+
.col-xs-4
|
41
|
+
%label{ for: :obj_type }
|
42
|
+
obj_type
|
43
|
+
= link_to "X", params.except(:obj_type)
|
44
|
+
= text_field_tag :obj_type, params[:obj_type], placeholder: "obj_type", class: 'form-control'
|
45
|
+
.col-xs-4
|
46
|
+
%label{ for: :obj_id }
|
47
|
+
obj_id
|
48
|
+
= link_to "X", params.except(:obj_id)
|
49
|
+
= text_field_tag :obj_id, params[:obj_id], placeholder: "obj_id", class: 'form-control'
|
50
|
+
.col-xs-4
|
51
|
+
%label{ for: :referer }
|
52
|
+
referer
|
53
|
+
= link_to "X", params.except(:referer)
|
54
|
+
= text_field_tag :referer, params[:referer], placeholder: "referer", class: 'form-control'
|
55
|
+
.form-group
|
56
|
+
.row
|
57
|
+
.col-xs-3
|
58
|
+
%label{ for: :date_start }
|
59
|
+
Дата (от)
|
60
|
+
= link_to "X", params.except(:date_start)
|
61
|
+
= text_field_tag :date_start, params[:date_start], data: { role: :date_start }, placeholder: "Дата (от)", class: 'form-control'
|
62
|
+
.col-xs-3
|
63
|
+
%label{ for: :date_end }
|
64
|
+
Дата (до)
|
65
|
+
= link_to "X", params.except(:date_end)
|
66
|
+
= text_field_tag :date_end, params[:date_end], data: { role: :date_end }, placeholder: "Дата (до)", class: 'form-control'
|
67
|
+
.panel-footer
|
68
|
+
= submit_tag "Выбор", name: nil, class: 'btn btn-primary'
|
69
|
+
= link_to "Сбросить фильтры", params.except(:user_id, :date_start, :date_end, :sort_column, :sort_type, :ip, :fullpath, :referer, :user_agent, :referer, :controller_action, :created_at, :obj_id), class: 'btn btn-default'
|
70
|
+
|
71
|
+
%table.table.table-striped.table-hover
|
72
|
+
%thead
|
73
|
+
%tr
|
74
|
+
%th User
|
75
|
+
%th Obj
|
76
|
+
%th@ctrl_acts
|
77
|
+
- opts = options_for_select @ctrl_acts.collect{|opt| base_name = [ opt.controller_name, opt.action_name ].join(':'); [ "#{ base_name } (#{ opt.count })", base_name ] }, selected: params[:controller_action]
|
78
|
+
= select_tag :controller_action, opts, prompt: "Controller/Action", class: 'form-control'
|
79
|
+
%th= link_to 'Fullpath↕', simple_sort_url(:fullpath, params), title: :fullpath
|
80
|
+
|
81
|
+
%th= link_to 'IP↕', simple_sort_url(:ip, params), title: :description
|
82
|
+
%th= link_to 'Referer↕', simple_sort_url(:referer, params), title: :referer
|
83
|
+
%th= link_to 'User agent↕', simple_sort_url(:user_agent, params), title: :user_agent
|
84
|
+
%th= link_to 'created_at↕', simple_sort_url(:created_at, params), title: :created_at
|
85
|
+
%th Action
|
86
|
+
|
87
|
+
%tbody
|
88
|
+
- @audits.each do |audit|
|
89
|
+
%tr
|
90
|
+
%td
|
91
|
+
- if audit.user
|
92
|
+
= link_to audit.user_name, params.merge(user_id: audit.user_id)
|
93
|
+
/ = link_to audit.user_name, audit.user_path(self)
|
94
|
+
- else
|
95
|
+
Guest
|
96
|
+
|
97
|
+
%td
|
98
|
+
- if audit.obj_type.present?
|
99
|
+
- l_1 = link_to audit.obj_type, params.merge(obj_type: audit.obj_type)
|
100
|
+
- l_2 = link_to audit.obj_id, params.merge(obj_id: audit.obj_id)
|
101
|
+
- l_3 = link_to '[all]', params.merge(obj_type: audit.obj_type, obj_id: audit.obj_id)
|
102
|
+
#{ l_1 }:#{ l_2 } #{ l_3 }
|
103
|
+
|
104
|
+
%td= [ audit.controller_name, audit.action_name ].join ':'
|
105
|
+
%td{ title: audit.fullpath }= audit.fullpath.to_s[0..30]
|
106
|
+
|
107
|
+
%td= link_to audit.ip, params.merge(ip: audit.ip)
|
108
|
+
|
109
|
+
%td{ title: audit.referer }
|
110
|
+
= link_to audit.referer.to_s[0..30], params.merge(referer: audit.referer)
|
111
|
+
|
112
|
+
%td{ title: audit.user_agent }
|
113
|
+
- agent = bot_marker(audit.user_agent) || audit.user_agent.to_s[0..30]
|
114
|
+
= link_to agent, params.merge(user_agent: audit.user_agent)
|
115
|
+
|
116
|
+
%td= audit.created_at.to_s(:db)
|
117
|
+
%td= link_to('Show', audit_path(audit))
|
118
|
+
|
119
|
+
= paginate @audits
|
@@ -0,0 +1,73 @@
|
|
1
|
+
%h1= t("the_audit.show_record")
|
2
|
+
|
3
|
+
- content_for :the_audit_main do
|
4
|
+
-# #TODO set bootstrap style for notice
|
5
|
+
%p#notice= notice
|
6
|
+
|
7
|
+
%table.table.table-striped
|
8
|
+
%tbody
|
9
|
+
%tr
|
10
|
+
%td
|
11
|
+
%strong User:
|
12
|
+
%td
|
13
|
+
-# #TODO show Guest unless User present
|
14
|
+
= @audit.user_id
|
15
|
+
%tr
|
16
|
+
%td
|
17
|
+
%strong Obj:
|
18
|
+
%td
|
19
|
+
= @audit.obj_id
|
20
|
+
%tr
|
21
|
+
%td
|
22
|
+
%strong Obj type:
|
23
|
+
%td
|
24
|
+
= @audit.obj_type
|
25
|
+
%tr
|
26
|
+
%td
|
27
|
+
%strong Controller name:
|
28
|
+
%td
|
29
|
+
= @audit.controller_name
|
30
|
+
%tr
|
31
|
+
%td
|
32
|
+
%strong Action name:
|
33
|
+
%td
|
34
|
+
= @audit.action_name
|
35
|
+
%tr
|
36
|
+
%td
|
37
|
+
%strong IP:
|
38
|
+
%td
|
39
|
+
= @audit.ip
|
40
|
+
%tr
|
41
|
+
%td
|
42
|
+
%strong Remote IP:
|
43
|
+
%td
|
44
|
+
= @audit.remote_ip
|
45
|
+
%tr
|
46
|
+
%td
|
47
|
+
%strong Fullpath:
|
48
|
+
%td
|
49
|
+
= @audit.fullpath
|
50
|
+
%tr
|
51
|
+
%td
|
52
|
+
%strong Referer:
|
53
|
+
%td
|
54
|
+
= @audit.referer
|
55
|
+
%tr
|
56
|
+
%td
|
57
|
+
%strong User agent:
|
58
|
+
%td
|
59
|
+
= @audit.user_agent
|
60
|
+
%tr
|
61
|
+
%td
|
62
|
+
%strong Remote addr:
|
63
|
+
%td
|
64
|
+
= @audit.remote_addr
|
65
|
+
%tr
|
66
|
+
%td
|
67
|
+
%strong Data:
|
68
|
+
%td
|
69
|
+
= @audit.data
|
70
|
+
/#TODO maybe show buttons insted links
|
71
|
+
= link_to t('the_audit.edit'), edit_audit_path(@audit)
|
72
|
+
|
|
73
|
+
= link_to t('the_audit.list'), audits_path
|
data/config/routes.rb
ADDED
data/gem_version.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
Description:
|
2
|
+
This generators helps to install TheAudit gem into your Application
|
3
|
+
|
4
|
+
Usage: [bundle exec] rails g the_audit NAME
|
5
|
+
|
6
|
+
# This text:
|
7
|
+
> rails g the_audit --help
|
8
|
+
|
9
|
+
# Main generator:
|
10
|
+
> rails g the_audit install
|
11
|
+
|
12
|
+
This will create:
|
13
|
+
app/controllers/admin/audits_controller.rb
|
14
|
+
app/models/audit.rb
|
15
|
+
|
16
|
+
# Controller generators:
|
17
|
+
> rails g the_audit controller
|
18
|
+
|
19
|
+
This will create:
|
20
|
+
app/controllers/admin/audits_controller.rb
|
21
|
+
|
22
|
+
# Model generators:
|
23
|
+
> rails g the_audit model
|
24
|
+
|
25
|
+
This will create:
|
26
|
+
app/models/audit.rb
|
27
|
+
|
28
|
+
# Migrations:
|
29
|
+
> rake the_audit_engine:install:migrations
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class TheAuditGenerator < Rails::Generators::NamedBase
|
2
|
+
source_root File.expand_path('../templates', __FILE__)
|
3
|
+
# argument :xname, type: :string, default: :xname
|
4
|
+
|
5
|
+
# > rails g the_comments NAME
|
6
|
+
def generate_controllers
|
7
|
+
case gen_name
|
8
|
+
when 'model'
|
9
|
+
cp_model
|
10
|
+
when 'controller'
|
11
|
+
cp_controller
|
12
|
+
when 'install'
|
13
|
+
cp_model
|
14
|
+
cp_controller
|
15
|
+
else
|
16
|
+
puts 'TheAudit Generator - wrong Name'
|
17
|
+
puts 'Try to use [ install | controller | model ]'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def root_path; TheAudit::Engine.root; end
|
24
|
+
|
25
|
+
def gen_name
|
26
|
+
name.to_s.downcase
|
27
|
+
end
|
28
|
+
|
29
|
+
def cp_model
|
30
|
+
copy_file "#{root_path}/app/models/_templates_/audit.rb",
|
31
|
+
"app/models/audit.rb"
|
32
|
+
end
|
33
|
+
|
34
|
+
def cp_controller
|
35
|
+
copy_file "#{root_path}/app/controllers/_templates_/audits_controller.rb",
|
36
|
+
"app/controllers/admin/audits_controller.rb"
|
37
|
+
end
|
38
|
+
end
|
data/lib/tasks/bots.rake
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# rake the_audit:bots:recalc
|
2
|
+
namespace :the_audit do
|
3
|
+
namespace :bots do
|
4
|
+
# rake bots:recalc
|
5
|
+
desc "Recalculate Audit Bot flags"
|
6
|
+
|
7
|
+
task recalc: :environment do
|
8
|
+
acount = Audit.count
|
9
|
+
bsize = 1000
|
10
|
+
Audit.find_in_batches(batch_size: bsize).with_index do |group, index|
|
11
|
+
group.each do |audit|
|
12
|
+
bot_flag = TheAudit.is_bot?(audit.user_agent)
|
13
|
+
|
14
|
+
if audit.bot != bot_flag
|
15
|
+
audit.update_column(:bot, bot_flag)
|
16
|
+
p "Updated: #{ audit.id }/#{ audit.user_agent }"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
p "#{ bsize * index.next }/#{ acount }"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/the_audit.rb
CHANGED
@@ -1,4 +1,22 @@
|
|
1
|
-
require "the_audit/engine"
|
2
1
|
require "the_audit/version"
|
3
2
|
|
4
|
-
module TheAudit
|
3
|
+
module TheAudit
|
4
|
+
def self.is_bot? user_agent
|
5
|
+
!!user_agent.to_s.match(/bot|riddler|crawler|spider|slurp|fetcher/mix)
|
6
|
+
end
|
7
|
+
|
8
|
+
class Engine < Rails::Engine; end
|
9
|
+
# initializer "Assets precompile hook", :group => :all do |app|
|
10
|
+
# app.config.assets.precompile += %w( file.js file.css )
|
11
|
+
# end
|
12
|
+
end
|
13
|
+
|
14
|
+
_root_ = File.expand_path('../../', __FILE__)
|
15
|
+
|
16
|
+
# Loading of concerns
|
17
|
+
require "#{_root_}/app/controllers/concerns/controller.rb"
|
18
|
+
require "#{_root_}/config/routes.rb"
|
19
|
+
|
20
|
+
%w[ base ].each do |concern|
|
21
|
+
require "#{_root_}/app/models/concerns/#{concern}.rb"
|
22
|
+
end
|
data/lib/the_audit/version.rb
CHANGED
data/pic.png
ADDED
Binary file
|
data/the_audit.gemspec
CHANGED
@@ -16,4 +16,7 @@ Gem::Specification.new do |gem|
|
|
16
16
|
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
17
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
18
|
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_dependency 'haml'
|
21
|
+
gem.add_dependency 'the_pagination'
|
19
22
|
end
|
metadata
CHANGED
@@ -1,16 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: the_audit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.0.2
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Ilya N. Zykin
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
13
|
-
dependencies:
|
11
|
+
date: 2014-06-22 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: haml
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: the_pagination
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
14
41
|
description: Collect basic request info in Rails app
|
15
42
|
email:
|
16
43
|
- zykin-ilya@ya.ru
|
@@ -18,39 +45,54 @@ executables: []
|
|
18
45
|
extensions: []
|
19
46
|
extra_rdoc_files: []
|
20
47
|
files:
|
21
|
-
- .gitignore
|
48
|
+
- ".gitignore"
|
22
49
|
- Gemfile
|
23
50
|
- LICENSE.txt
|
24
51
|
- README.md
|
25
52
|
- Rakefile
|
26
|
-
- app/
|
53
|
+
- app/assets/javascripts/the_audit.js.coffee
|
54
|
+
- app/controllers/_templates_/audits_controller.rb
|
55
|
+
- app/controllers/concerns/controller.rb
|
56
|
+
- app/helpers/the_audit_helper.rb
|
57
|
+
- app/models/_templates_/audit.rb
|
58
|
+
- app/models/concerns/base.rb
|
59
|
+
- app/views/audits/_form.html.haml
|
60
|
+
- app/views/audits/edit.html.haml
|
61
|
+
- app/views/audits/index.html.haml
|
62
|
+
- app/views/audits/show.html.haml
|
63
|
+
- config/locales/en.yml
|
64
|
+
- config/locales/ru.yml
|
65
|
+
- config/routes.rb
|
27
66
|
- db/migrate/20130130163149_create_audits.rb
|
67
|
+
- gem_version.rb
|
68
|
+
- lib/generators/the_audit/USAGE
|
69
|
+
- lib/generators/the_audit/the_audit_generator.rb
|
70
|
+
- lib/tasks/bots.rake
|
28
71
|
- lib/the_audit.rb
|
29
|
-
- lib/the_audit/engine.rb
|
30
72
|
- lib/the_audit/version.rb
|
73
|
+
- pic.png
|
31
74
|
- the_audit.gemspec
|
32
75
|
homepage: https://github.com/the-teacher
|
33
76
|
licenses: []
|
77
|
+
metadata: {}
|
34
78
|
post_install_message:
|
35
79
|
rdoc_options: []
|
36
80
|
require_paths:
|
37
81
|
- lib
|
38
82
|
required_ruby_version: !ruby/object:Gem::Requirement
|
39
|
-
none: false
|
40
83
|
requirements:
|
41
|
-
- -
|
84
|
+
- - ">="
|
42
85
|
- !ruby/object:Gem::Version
|
43
86
|
version: '0'
|
44
87
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
45
|
-
none: false
|
46
88
|
requirements:
|
47
|
-
- -
|
89
|
+
- - ">="
|
48
90
|
- !ruby/object:Gem::Version
|
49
91
|
version: '0'
|
50
92
|
requirements: []
|
51
93
|
rubyforge_project:
|
52
|
-
rubygems_version:
|
94
|
+
rubygems_version: 2.2.2
|
53
95
|
signing_key:
|
54
|
-
specification_version:
|
96
|
+
specification_version: 4
|
55
97
|
summary: Collect basic request info in Rails app
|
56
98
|
test_files: []
|
data/app/models/audit.rb
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
class Audit < ActiveRecord::Base
|
2
|
-
belongs_to :user
|
3
|
-
belongs_to :obj, polymorphic: true
|
4
|
-
|
5
|
-
def init controller, object = nil, data = {}
|
6
|
-
self.obj = object
|
7
|
-
self.action_name = controller.action_name
|
8
|
-
self.controller_name = controller.controller_name
|
9
|
-
|
10
|
-
self.data = data.to_json unless data.blank?
|
11
|
-
|
12
|
-
if r = controller.request
|
13
|
-
self.ip = r.ip
|
14
|
-
self.user_agent = r.user_agent
|
15
|
-
self.remote_ip = r.remote_ip
|
16
|
-
self.remote_addr = r.remote_addr
|
17
|
-
self.remote_host = r.remote_host
|
18
|
-
self.fullpath = CGI::unescape(r.fullpath || '')
|
19
|
-
self.referer = CGI::unescape(r.referer || 'direct_visit')
|
20
|
-
end
|
21
|
-
|
22
|
-
self
|
23
|
-
end
|
24
|
-
end
|
data/lib/the_audit/engine.rb
DELETED