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.
@@ -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
@@ -15,3 +15,4 @@ spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
+ .DS_Store
data/README.md CHANGED
@@ -1,8 +1,174 @@
1
- # TheAudit
1
+ # TheAudit - collect user's request info
2
2
 
3
- bundle gem the_audit
4
- # create => gem
3
+ ### Простой, расширяемый
4
+ [#TODO clarify this sentence]
5
5
 
6
- add engine init file lib/NAME/engine.rb and requires
7
- # => bundle exec rake the_audit_engine:install:migrations
8
- # => bundle exec rake db:migrate
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,3 @@
1
+ class Admin::AuditsController < ApplicationController
2
+ include TheAudit::Controller
3
+ end
@@ -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,3 @@
1
+ class Audit < ActiveRecord::Base
2
+ include TheAudit::Base
3
+ 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,6 @@
1
+ %h1= t('the_audit.edit')
2
+ %p= link_to t('the_audit.list'), audits_path
3
+
4
+ - content_for :the_audit_main do
5
+
6
+ = render 'form'
@@ -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 }&nbsp;#{ 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
@@ -0,0 +1,7 @@
1
+ en:
2
+ the_audit:
3
+ list: All records
4
+ edit: Edit record
5
+ save: Save
6
+ list_title: Audit
7
+ show_record: Show audit record
@@ -0,0 +1,7 @@
1
+ ru:
2
+ the_audit:
3
+ list: Все записи
4
+ edit: Редактировать запись
5
+ save: Сохранить
6
+ list_title: Аудит
7
+ show_record: Просмотр записи аудита
@@ -0,0 +1,9 @@
1
+ # TheAudit::Routes.mixin(self)
2
+ module TheAudit
3
+ class Routes
4
+ def self.mixin mapper
5
+ mapper.resources :audits, except: %w[ new create ]
6
+ end
7
+ end
8
+ end
9
+
@@ -13,7 +13,10 @@ class CreateAudits < ActiveRecord::Migration
13
13
  t.string :remote_ip
14
14
  t.string :fullpath
15
15
  t.string :referer
16
- t.string :user_agent
16
+
17
+ t.boolean :bot, default: false
18
+ t.string :user_agent
19
+
17
20
  t.string :remote_addr
18
21
  t.string :remote_host
19
22
 
@@ -0,0 +1,3 @@
1
+ module TheAudit
2
+ VERSION = "0.0.2"
3
+ end
@@ -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
@@ -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
@@ -1,4 +1,22 @@
1
- require "the_audit/engine"
2
1
  require "the_audit/version"
3
2
 
4
- module TheAudit; end
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
@@ -1,3 +1 @@
1
- module TheAudit
2
- VERSION = "0.0.1"
3
- end
1
+ require_relative '../../gem_version'
data/pic.png ADDED
Binary file
@@ -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.1
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: 2013-08-23 00:00:00.000000000 Z
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/models/audit.rb
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: 1.8.15
94
+ rubygems_version: 2.2.2
53
95
  signing_key:
54
- specification_version: 3
96
+ specification_version: 4
55
97
  summary: Collect basic request info in Rails app
56
98
  test_files: []
@@ -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
@@ -1,10 +0,0 @@
1
- require 'the_audit'
2
- require 'rails'
3
-
4
- module TheAudit
5
- class Engine < Rails::Engine
6
- # initializer "Assets precompile hook", :group => :all do |app|
7
- # app.config.assets.precompile += %w( file.js file.css )
8
- # end
9
- end
10
- end