Commit a9053d54 authored by Aishwarya Subramanian's avatar Aishwarya Subramanian

Tracking unique visits in Compliance Dashboard

Adds unique visitor tracking in Audit Events (group and instance),
Compliance Dashboard, and the Credential Inventory pages
parent b1e4c446
......@@ -4,9 +4,12 @@ class Admin::AuditLogsController < Admin::ApplicationController
include AuditEvents::EnforcesValidDateParams
include AuditEvents::AuditLogsParams
include AuditEvents::Sortable
include Analytics::UniqueVisitsHelper
before_action :check_license_admin_audit_log_available!
track_unique_visits :index, target_id: 'i_analytics_audit_events'
PER_PAGE = 25
def index
......
......@@ -3,11 +3,14 @@
class Admin::CredentialsController < Admin::ApplicationController
extend ::Gitlab::Utils::Override
include CredentialsInventoryActions
include Analytics::UniqueVisitsHelper
helper_method :credentials_inventory_path, :user_detail_path
before_action :check_license_credentials_inventory_available!, only: [:index]
track_unique_visits :index, target_id: 'i_analytics_credential_inventory'
private
def check_license_credentials_inventory_available!
......
......@@ -7,7 +7,11 @@ module CredentialsInventoryActions
def index
@credentials = filter_credentials.page(params[:page]).preload_users.without_count # rubocop:disable Gitlab/ModuleWithInstanceVariables
render 'shared/credentials_inventory/index'
respond_to do |format|
format.html do
render 'shared/credentials_inventory/index'
end
end
end
private
......
......@@ -4,10 +4,13 @@ class Groups::AuditEventsController < Groups::ApplicationController
include AuditEvents::EnforcesValidDateParams
include AuditEvents::AuditLogsParams
include AuditEvents::Sortable
include Analytics::UniqueVisitsHelper
before_action :authorize_admin_group!
before_action :check_audit_events_available!
track_unique_visits :index, target_id: 'g_analytics_audit_events'
layout 'group_settings'
def index
......
# frozen_string_literal: true
class Groups::Security::ComplianceDashboardsController < Groups::ApplicationController
include Groups::SecurityFeaturesHelper
include Analytics::UniqueVisitsHelper
layout 'group'
before_action :authorize_compliance_dashboard!
track_unique_visits :show, target_id: 'g_analytics_compliance_dashboard'
def show
@last_page = paginated_merge_requests.last_page?
@merge_requests = serialize(paginated_merge_requests)
......
---
title: Track unique visitors in Compliance related pages
merge_request: 38851
author:
type: added
......@@ -24,6 +24,11 @@ RSpec.describe Admin::AuditLogsController do
expect(assigns(:events)).to be_kind_of(Kaminari::PaginatableWithoutCount)
end
end
it_behaves_like 'tracking unique visits', :index do
let(:request_params) { { 'entity_type': 'User' } }
let(:target_id) { 'i_analytics_audit_events' }
end
end
end
end
......@@ -20,6 +20,11 @@ RSpec.describe Admin::CredentialsController do
expect(response).to have_gitlab_http_status(:ok)
end
it_behaves_like 'tracking unique visits', :index do
let(:request_params) { {} }
let(:target_id) { 'i_analytics_credential_inventory' }
end
describe 'filtering by type of credential' do
let_it_be(:personal_access_tokens) { create_list(:personal_access_token, 2) }
......
......@@ -12,113 +12,124 @@ RSpec.describe Groups::AuditEventsController do
let(:entity_type) { nil }
let(:entity_id) { nil }
let(:request) do
get :index, params: { group_id: group.to_param, sort: sort, entity_type: entity_type, entity_id: entity_id }
end
context 'authorized' do
before do
group.add_owner(owner)
sign_in(owner)
end
context 'when audit_events feature is available' do
let(:level) { Gitlab::Audit::Levels::Group.new(group: group) }
let(:audit_logs_params) { ActionController::Parameters.new(sort: '', entity_type: '', entity_id: '').permit! }
before do
stub_licensed_features(audit_events: true)
allow(Gitlab::Audit::Levels::Group).to receive(:new).and_return(level)
allow(AuditLogFinder).to receive(:new).and_call_original
context do
let(:request) do
get :index, params: { group_id: group.to_param, sort: sort, entity_type: entity_type, entity_id: entity_id }
end
shared_examples 'AuditLogFinder params' do
it 'has the correct params' do
request
context 'when audit_events feature is available' do
let(:level) { Gitlab::Audit::Levels::Group.new(group: group) }
let(:audit_logs_params) { ActionController::Parameters.new(sort: '', entity_type: '', entity_id: '').permit! }
expect(AuditLogFinder).to have_received(:new).with(
level: level, params: audit_logs_params
)
before do
stub_licensed_features(audit_events: true)
allow(Gitlab::Audit::Levels::Group).to receive(:new).and_return(level)
allow(AuditLogFinder).to receive(:new).and_call_original
end
end
it 'renders index with 200 status code' do
request
shared_examples 'AuditLogFinder params' do
it 'has the correct params' do
request
expect(response).to have_gitlab_http_status(:ok)
expect(response).to render_template(:index)
end
expect(AuditLogFinder).to have_received(:new).with(
level: level, params: audit_logs_params
)
end
end
context 'invokes AuditLogFinder with correct arguments' do
it_behaves_like 'AuditLogFinder params'
end
it 'renders index with 200 status code' do
request
context 'author' do
context 'when no author entity type is specified' do
it_behaves_like 'AuditLogFinder params'
expect(response).to have_gitlab_http_status(:ok)
expect(response).to render_template(:index)
end
context 'when the author entity type is specified' do
let(:entity_type) { 'Author' }
let(:entity_id) { 1 }
let(:audit_logs_params) { ActionController::Parameters.new(sort: '', author_id: '1').permit! }
context 'invokes AuditLogFinder with correct arguments' do
it_behaves_like 'AuditLogFinder params'
end
end
context 'ordering' do
shared_examples 'orders by id descending' do
it 'orders by id descending' do
request
context 'author' do
context 'when no author entity type is specified' do
it_behaves_like 'AuditLogFinder params'
end
expect(assigns(:events)).to eq(group.audit_events.order(id: :desc))
context 'when the author entity type is specified' do
let(:entity_type) { 'Author' }
let(:entity_id) { 1 }
let(:audit_logs_params) { ActionController::Parameters.new(sort: '', author_id: '1').permit! }
it_behaves_like 'AuditLogFinder params'
end
end
before do
create_list(:group_audit_event, 5, entity_id: group.id)
end
context 'ordering' do
shared_examples 'orders by id descending' do
it 'orders by id descending' do
request
context 'when no sort order is specified' do
it_behaves_like 'orders by id descending'
end
expect(assigns(:events)).to eq(group.audit_events.order(id: :desc))
end
end
context 'when sorting by latest events first' do
let(:sort) { 'created_desc' }
before do
create_list(:group_audit_event, 5, entity_id: group.id)
end
it_behaves_like 'orders by id descending'
end
context 'when no sort order is specified' do
it_behaves_like 'orders by id descending'
end
context 'when sorting by oldest events first' do
let(:sort) { 'created_asc' }
context 'when sorting by latest events first' do
let(:sort) { 'created_desc' }
it 'orders by id ascending' do
request
it_behaves_like 'orders by id descending'
end
context 'when sorting by oldest events first' do
let(:sort) { 'created_asc' }
it 'orders by id ascending' do
request
expect(assigns(:events)).to eq(group.audit_events.order(id: :asc))
expect(assigns(:events)).to eq(group.audit_events.order(id: :asc))
end
end
end
context 'when sorting by an unsupported sort order' do
let(:sort) { 'FOO' }
context 'when sorting by an unsupported sort order' do
let(:sort) { 'FOO' }
it_behaves_like 'orders by id descending'
it_behaves_like 'orders by id descending'
end
end
end
context 'pagination' do
it 'paginates audit events, without casting a count query' do
request
context 'pagination' do
it 'paginates audit events, without casting a count query' do
request
expect(assigns(:events)).to be_kind_of(Kaminari::PaginatableWithoutCount)
expect(assigns(:events)).to be_kind_of(Kaminari::PaginatableWithoutCount)
end
end
end
end
it_behaves_like 'tracking unique visits', :index do
let(:request_params) { { group_id: group.to_param, sort: sort, entity_type: entity_type, entity_id: entity_id } }
let(:target_id) { 'g_analytics_audit_events' }
end
end
context 'unauthorized' do
let(:request) do
get :index, params: { group_id: group.to_param, sort: sort, entity_type: entity_type, entity_id: entity_id }
end
before do
stub_licensed_features(audit_events: true)
sign_in(user)
......
......@@ -47,6 +47,11 @@ RSpec.describe Groups::Security::ComplianceDashboardsController do
expect(assigns(:merge_requests)).not_to be_empty
end
end
it_behaves_like 'tracking unique visits', :show do
let(:request_params) { { group_id: group.to_param } }
let(:target_id) { 'g_analytics_compliance_dashboard' }
end
end
context 'when user is not allowed to access group compliance dashboard' do
......
......@@ -9,6 +9,8 @@ module Gitlab
'g_analytics_issues',
'g_analytics_productivity',
'g_analytics_valuestream',
'g_analytics_compliance_dashboard',
'g_analytics_audit_events',
'p_analytics_pipelines',
'p_analytics_code_reviews',
'p_analytics_valuestream',
......@@ -16,7 +18,9 @@ module Gitlab
'p_analytics_issues',
'p_analytics_repo',
'i_analytics_cohorts',
'i_analytics_dev_ops_score'
'i_analytics_dev_ops_score',
'i_analytics_credential_inventory',
'i_analytics_audit_events'
].freeze
KEY_EXPIRY_LENGTH = 12.weeks
......
......@@ -975,11 +975,15 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
'p_analytics_pipelines' => 123,
'p_analytics_code_reviews' => 123,
'p_analytics_valuestream' => 123,
'g_analytics_compliance_dashboard' => 123,
'g_analytics_audit_events' => 123,
'p_analytics_insights' => 123,
'p_analytics_issues' => 123,
'p_analytics_repo' => 123,
'i_analytics_cohorts' => 123,
'i_analytics_dev_ops_score' => 123,
'i_analytics_credential_inventory' => 123,
'i_analytics_audit_events' => 123,
'analytics_unique_visits_for_any_target' => 543,
'analytics_unique_visits_for_any_target_monthly' => 987
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment