trackguard 0.19.0 → 0.20.0
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.
- checksums.yaml +4 -4
- data/app/controllers/concerns/trackguard/admin/overridable.rb +29 -0
- data/app/controllers/trackguard/admin/analytics_controller.rb +30 -35
- data/app/controllers/trackguard/admin/blocked_user_agents_controller.rb +1 -1
- data/app/controllers/trackguard/admin/dashboards_controller.rb +14 -8
- data/app/controllers/trackguard/admin/visitors_controller.rb +7 -13
- data/app/controllers/trackguard/admin/visits_controller.rb +7 -5
- data/app/controllers/trackguard/admin/whitelisted_ips_controller.rb +8 -14
- data/app/services/trackguard/analytics_query.rb +27 -0
- data/lib/generators/trackguard/templates/create_trackguard_tables.rb +1 -0
- data/lib/trackguard/version.rb +1 -1
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3e13b68029bc80d015c4f69531d17e5b362092d6df2d720dfb7c1563b5b4e24c
|
|
4
|
+
data.tar.gz: e676a88de14a04d1c42c0a78f7e895a7ef5011c7567e93a168e82e8f950bfeb1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d4074d349ac565380d3365ef21ca99e61836601f51fe5822cff34a3184f93cea71dc0ab541b2a08f2f0ccb49fade36c89a97f8681a5609748088ecdb661f6f84
|
|
7
|
+
data.tar.gz: 1783d02fa8caedd5816efce4cca6faab7c305af260549de8ece369c22ff47b279725e9503dc5c3d8cade1f5069516faaee594fd362e16b92939317168f4d7dfc
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module Trackguard
|
|
2
|
+
module Admin
|
|
3
|
+
module Overridable
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
|
|
6
|
+
private
|
|
7
|
+
|
|
8
|
+
def visitor_scope
|
|
9
|
+
Visitor.all
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def page_view_scope
|
|
13
|
+
PageView.all
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def after_action_path
|
|
17
|
+
dashboard_path
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def set_visitor
|
|
21
|
+
@visitor = if params[:ip].present?
|
|
22
|
+
visitor_scope.find_by!(ip: params[:ip])
|
|
23
|
+
else
|
|
24
|
+
visitor_scope.find(params[:id])
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -1,46 +1,25 @@
|
|
|
1
1
|
module Trackguard
|
|
2
2
|
module Admin
|
|
3
3
|
class AnalyticsController < BaseController
|
|
4
|
+
include Overridable
|
|
5
|
+
|
|
4
6
|
skip_before_action :verify_authenticity_token, if: :valid_api_token?
|
|
5
7
|
|
|
6
|
-
# rubocop:disable Metrics/AbcSize
|
|
7
8
|
def show
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
base = time_scope
|
|
13
|
-
@top_pages = base.group(:path).order("count_all DESC").limit(10).count
|
|
14
|
-
@top_referrers = base.with_referrer.group(:referer).order("count_all DESC").limit(10).count
|
|
15
|
-
@top_sources = base.with_source.group(:source).order("count_all DESC").limit(10).count
|
|
16
|
-
|
|
17
|
-
@recent = visitor_filtered(
|
|
18
|
-
time_scope(PageView.order(created_at: :desc).limit(20).includes(visitor: :whitelisted_ip))
|
|
9
|
+
query = AnalyticsQuery.call(
|
|
10
|
+
scope: page_view_scope,
|
|
11
|
+
time_scope: apply_time_scope(page_view_scope),
|
|
12
|
+
limit: 10
|
|
19
13
|
)
|
|
20
14
|
|
|
21
15
|
render json: {
|
|
22
|
-
totals:
|
|
23
|
-
top_pages:
|
|
24
|
-
top_referrers:
|
|
25
|
-
top_sources:
|
|
26
|
-
recent:
|
|
27
|
-
{
|
|
28
|
-
path: pv.path,
|
|
29
|
-
ip: pv.visitor&.ip,
|
|
30
|
-
flagged_at: pv.visitor.flagged_at,
|
|
31
|
-
flagged_by: pv.visitor.flagged_by,
|
|
32
|
-
whitelisted: pv.visitor.whitelisted_ip&.active? || false,
|
|
33
|
-
user_agent: pv.user_agent,
|
|
34
|
-
session_id: pv.session_id,
|
|
35
|
-
trace_id: pv.trace_id,
|
|
36
|
-
referer: pv.referer,
|
|
37
|
-
source: pv.source,
|
|
38
|
-
created_at: pv.created_at
|
|
39
|
-
}
|
|
40
|
-
end
|
|
16
|
+
totals: query.totals,
|
|
17
|
+
top_pages: query.top_pages,
|
|
18
|
+
top_referrers: query.top_referrers,
|
|
19
|
+
top_sources: query.top_sources,
|
|
20
|
+
recent: visitor_filtered(apply_time_scope(query.recent)).map { |view| serialize_page_view(view) }
|
|
41
21
|
}
|
|
42
22
|
end
|
|
43
|
-
# rubocop:enable Metrics/AbcSize
|
|
44
23
|
|
|
45
24
|
private
|
|
46
25
|
|
|
@@ -50,7 +29,7 @@ module Trackguard
|
|
|
50
29
|
super
|
|
51
30
|
end
|
|
52
31
|
|
|
53
|
-
def
|
|
32
|
+
def apply_time_scope(base)
|
|
54
33
|
params[:since].present? ? base.where(created_at: parsed_since..) : base.last_30
|
|
55
34
|
end
|
|
56
35
|
|
|
@@ -64,8 +43,8 @@ module Trackguard
|
|
|
64
43
|
|
|
65
44
|
def visitor_filtered(scope)
|
|
66
45
|
if params.key?(:flagged)
|
|
67
|
-
|
|
68
|
-
scope = scope.joins(:visitor).merge(
|
|
46
|
+
flagged_scope = cast_bool(params[:flagged]) ? Visitor.flagged : Visitor.unflagged
|
|
47
|
+
scope = scope.joins(:visitor).merge(flagged_scope)
|
|
69
48
|
end
|
|
70
49
|
if params.key?(:whitelisted)
|
|
71
50
|
scope = if cast_bool(params[:whitelisted])
|
|
@@ -80,6 +59,22 @@ module Trackguard
|
|
|
80
59
|
def cast_bool(val)
|
|
81
60
|
ActiveRecord::Type::Boolean.new.cast(val)
|
|
82
61
|
end
|
|
62
|
+
|
|
63
|
+
def serialize_page_view(view)
|
|
64
|
+
{
|
|
65
|
+
path: view.path,
|
|
66
|
+
ip: view.visitor&.ip,
|
|
67
|
+
flagged_at: view.visitor.flagged_at,
|
|
68
|
+
flagged_by: view.visitor.flagged_by,
|
|
69
|
+
whitelisted: view.visitor.whitelisted_ip&.active? || false,
|
|
70
|
+
user_agent: view.user_agent,
|
|
71
|
+
session_id: view.session_id,
|
|
72
|
+
trace_id: view.trace_id,
|
|
73
|
+
referer: view.referer,
|
|
74
|
+
source: view.source,
|
|
75
|
+
created_at: view.created_at
|
|
76
|
+
}
|
|
77
|
+
end
|
|
83
78
|
end
|
|
84
79
|
end
|
|
85
80
|
end
|
|
@@ -12,7 +12,7 @@ module Trackguard
|
|
|
12
12
|
Rails.cache.delete(BlockedUserAgent::CACHE_KEY)
|
|
13
13
|
render json: { status: "ok", pattern: record.pattern }
|
|
14
14
|
rescue ActionController::ParameterMissing, ActiveRecord::RecordInvalid => e
|
|
15
|
-
render json: { status: "error", message: e.message }, status: :
|
|
15
|
+
render json: { status: "error", message: e.message }, status: :unprocessable_content
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
private
|
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
module Trackguard
|
|
2
2
|
module Admin
|
|
3
3
|
class DashboardsController < BaseController
|
|
4
|
-
|
|
5
|
-
@total_today = PageView.today.count
|
|
6
|
-
@total_week = PageView.this_week.count
|
|
7
|
-
@total_month = PageView.this_month.count
|
|
4
|
+
include Overridable
|
|
8
5
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
def show
|
|
7
|
+
query = AnalyticsQuery.call(
|
|
8
|
+
scope: page_view_scope,
|
|
9
|
+
time_scope: page_view_scope.last_30,
|
|
10
|
+
limit: 5
|
|
11
|
+
)
|
|
12
12
|
|
|
13
|
-
@
|
|
13
|
+
@total_today = query.totals[:today]
|
|
14
|
+
@total_week = query.totals[:week]
|
|
15
|
+
@total_month = query.totals[:month]
|
|
16
|
+
@top_pages = query.top_pages
|
|
17
|
+
@top_referrers = query.top_referrers
|
|
18
|
+
@top_sources = query.top_sources
|
|
19
|
+
@recent = query.recent
|
|
14
20
|
end
|
|
15
21
|
end
|
|
16
22
|
end
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
module Trackguard
|
|
2
2
|
module Admin
|
|
3
3
|
class VisitorsController < BaseController
|
|
4
|
+
include Overridable
|
|
5
|
+
|
|
4
6
|
skip_before_action :verify_authenticity_token, if: :valid_api_token?
|
|
5
7
|
before_action :set_visitor
|
|
6
8
|
|
|
7
9
|
rescue_from ActiveRecord::RecordNotFound do
|
|
8
10
|
respond_to do |format|
|
|
9
|
-
format.html { redirect_to
|
|
11
|
+
format.html { redirect_to after_action_path, alert: "Visitor not found." }
|
|
10
12
|
format.json { render json: { error: "Visitor not found" }, status: :not_found }
|
|
11
13
|
end
|
|
12
14
|
end
|
|
@@ -20,13 +22,13 @@ module Trackguard
|
|
|
20
22
|
name: params[:name].presence || BlockedUserAgent.matching_pattern(@visitor.user_agent)
|
|
21
23
|
)
|
|
22
24
|
respond_to do |format|
|
|
23
|
-
format.html { redirect_back_or_to
|
|
25
|
+
format.html { redirect_back_or_to after_action_path }
|
|
24
26
|
format.json { render json: { status: "ok", ip: @visitor.ip, flagged_at: @visitor.flagged_at } }
|
|
25
27
|
end
|
|
26
28
|
else
|
|
27
29
|
respond_to do |format|
|
|
28
|
-
format.html { redirect_back_or_to
|
|
29
|
-
format.json { render json: { errors: @visitor.errors.full_messages }, status: :
|
|
30
|
+
format.html { redirect_back_or_to after_action_path, alert: @visitor.errors.full_messages.join(", ") }
|
|
31
|
+
format.json { render json: { errors: @visitor.errors.full_messages }, status: :unprocessable_content }
|
|
30
32
|
end
|
|
31
33
|
end
|
|
32
34
|
end
|
|
@@ -35,7 +37,7 @@ module Trackguard
|
|
|
35
37
|
def unflag
|
|
36
38
|
@visitor.update!(flagged_at: nil, flag_reason: nil, flagged_by: nil)
|
|
37
39
|
respond_to do |format|
|
|
38
|
-
format.html { redirect_back_or_to
|
|
40
|
+
format.html { redirect_back_or_to after_action_path }
|
|
39
41
|
format.json { render json: { status: "ok", ip: @visitor.ip } }
|
|
40
42
|
end
|
|
41
43
|
end
|
|
@@ -47,14 +49,6 @@ module Trackguard
|
|
|
47
49
|
|
|
48
50
|
super
|
|
49
51
|
end
|
|
50
|
-
|
|
51
|
-
def set_visitor
|
|
52
|
-
@visitor = if params[:ip].present?
|
|
53
|
-
Visitor.find_by!(ip: params[:ip])
|
|
54
|
-
else
|
|
55
|
-
Visitor.find(params[:id])
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
52
|
end
|
|
59
53
|
end
|
|
60
54
|
end
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
module Trackguard
|
|
2
2
|
module Admin
|
|
3
3
|
class VisitsController < BaseController
|
|
4
|
+
include Overridable
|
|
5
|
+
|
|
4
6
|
PER_PAGE = 20
|
|
5
7
|
|
|
6
8
|
def index
|
|
7
9
|
@page = [ (params[:page] || 1).to_i, 1 ].max
|
|
8
|
-
@total =
|
|
10
|
+
@total = page_view_scope.count
|
|
9
11
|
@pages = (@total.to_f / PER_PAGE).ceil
|
|
10
|
-
@visits =
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
@visits = page_view_scope.order(created_at: :desc)
|
|
13
|
+
.limit(PER_PAGE)
|
|
14
|
+
.offset((@page - 1) * PER_PAGE)
|
|
15
|
+
.includes(visitor: :whitelisted_ip)
|
|
14
16
|
end
|
|
15
17
|
end
|
|
16
18
|
end
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
module Trackguard
|
|
2
2
|
module Admin
|
|
3
3
|
class WhitelistedIpsController < BaseController
|
|
4
|
+
include Overridable
|
|
5
|
+
|
|
4
6
|
skip_before_action :verify_authenticity_token, if: :valid_api_token?
|
|
5
7
|
before_action :set_visitor
|
|
6
8
|
|
|
7
9
|
rescue_from ActiveRecord::RecordNotFound do
|
|
8
10
|
respond_to do |format|
|
|
9
|
-
format.html { redirect_to
|
|
11
|
+
format.html { redirect_to after_action_path, alert: "Visitor not found." }
|
|
10
12
|
format.json { render json: { error: "Visitor not found" }, status: :not_found }
|
|
11
13
|
end
|
|
12
14
|
end
|
|
@@ -17,13 +19,13 @@ module Trackguard
|
|
|
17
19
|
record.expires_at = params[:expires_at].presence || 7.days.from_now
|
|
18
20
|
record.save!
|
|
19
21
|
respond_to do |format|
|
|
20
|
-
format.html { redirect_back_or_to
|
|
22
|
+
format.html { redirect_back_or_to after_action_path }
|
|
21
23
|
format.json { render json: { status: "ok", ip: @visitor.ip, expires_at: record.expires_at } }
|
|
22
24
|
end
|
|
23
25
|
rescue ActiveRecord::RecordInvalid => e
|
|
24
26
|
respond_to do |format|
|
|
25
|
-
format.html { redirect_back_or_to
|
|
26
|
-
format.json { render json: { status: "error", message: e.message }, status: :
|
|
27
|
+
format.html { redirect_back_or_to after_action_path, alert: e.message }
|
|
28
|
+
format.json { render json: { status: "error", message: e.message }, status: :unprocessable_content }
|
|
27
29
|
end
|
|
28
30
|
end
|
|
29
31
|
|
|
@@ -33,12 +35,12 @@ module Trackguard
|
|
|
33
35
|
if record
|
|
34
36
|
record.destroy!
|
|
35
37
|
respond_to do |format|
|
|
36
|
-
format.html { redirect_back_or_to
|
|
38
|
+
format.html { redirect_back_or_to after_action_path }
|
|
37
39
|
format.json { render json: { status: "ok", ip: @visitor.ip } }
|
|
38
40
|
end
|
|
39
41
|
else
|
|
40
42
|
respond_to do |format|
|
|
41
|
-
format.html { redirect_back_or_to
|
|
43
|
+
format.html { redirect_back_or_to after_action_path, alert: "No whitelist entry found." }
|
|
42
44
|
format.json { render json: { error: "Not whitelisted" }, status: :not_found }
|
|
43
45
|
end
|
|
44
46
|
end
|
|
@@ -51,14 +53,6 @@ module Trackguard
|
|
|
51
53
|
|
|
52
54
|
super
|
|
53
55
|
end
|
|
54
|
-
|
|
55
|
-
def set_visitor
|
|
56
|
-
@visitor = if params[:ip].present?
|
|
57
|
-
Visitor.find_by!(ip: params[:ip])
|
|
58
|
-
else
|
|
59
|
-
Visitor.find(params[:id])
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
56
|
end
|
|
63
57
|
end
|
|
64
58
|
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Trackguard
|
|
2
|
+
class AnalyticsQuery < ApplicationService
|
|
3
|
+
attr_reader :totals, :top_pages, :top_referrers, :top_sources, :recent
|
|
4
|
+
|
|
5
|
+
def initialize(scope:, time_scope:, limit:)
|
|
6
|
+
@scope = scope
|
|
7
|
+
@time_scope = time_scope
|
|
8
|
+
@limit = limit
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def call
|
|
12
|
+
@totals = {
|
|
13
|
+
today: @scope.today.count,
|
|
14
|
+
week: @scope.this_week.count,
|
|
15
|
+
month: @scope.this_month.count
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
@top_pages = @time_scope.group(:path).order("count_all DESC").limit(@limit).count
|
|
19
|
+
@top_referrers = @time_scope.with_referrer.group(:referer).order("count_all DESC").limit(@limit).count
|
|
20
|
+
@top_sources = @time_scope.with_source.group(:source).order("count_all DESC").limit(@limit).count
|
|
21
|
+
|
|
22
|
+
@recent = @scope.order(created_at: :desc).limit(20).includes(visitor: :whitelisted_ip)
|
|
23
|
+
|
|
24
|
+
self
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -2,6 +2,7 @@ class CreateTrackguardTables < ActiveRecord::Migration[<%= ActiveRecord::Migrati
|
|
|
2
2
|
def change
|
|
3
3
|
create_table :trackguard_visitors do |t|
|
|
4
4
|
t.string :ip
|
|
5
|
+
t.string :name
|
|
5
6
|
t.string :user_agent
|
|
6
7
|
t.datetime :first_seen_at, null: false
|
|
7
8
|
t.datetime :last_seen_at, null: false
|
data/lib/trackguard/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: trackguard
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.20.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Krzysztof Rygielski
|
|
@@ -46,6 +46,7 @@ files:
|
|
|
46
46
|
- app/assets/images/trackguard/logo.png
|
|
47
47
|
- app/assets/javascripts/controllers/page_tracker_controller.js
|
|
48
48
|
- app/assets/stylesheets/trackguard/admin.css
|
|
49
|
+
- app/controllers/concerns/trackguard/admin/overridable.rb
|
|
49
50
|
- app/controllers/concerns/trackguard/page_tracker.rb
|
|
50
51
|
- app/controllers/trackguard/admin/analytics_controller.rb
|
|
51
52
|
- app/controllers/trackguard/admin/base_controller.rb
|
|
@@ -65,6 +66,7 @@ files:
|
|
|
65
66
|
- app/models/trackguard/visit.rb
|
|
66
67
|
- app/models/trackguard/visitor.rb
|
|
67
68
|
- app/models/trackguard/whitelisted_ip.rb
|
|
69
|
+
- app/services/trackguard/analytics_query.rb
|
|
68
70
|
- app/services/trackguard/application_service.rb
|
|
69
71
|
- app/services/trackguard/page_view_recorder.rb
|
|
70
72
|
- app/views/layouts/trackguard/admin.html.erb
|