the_audit 0.0.1 → 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.
@@ -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