perf: Asset report

pull/15630/head
feng 2025-07-29 10:24:06 +08:00
parent 9631dec210
commit 66f74f9c30
5 changed files with 56 additions and 45 deletions

View File

@ -2,7 +2,7 @@
#
from collections import defaultdict
from django.db.models import Count, Q
from django.db.models import Count
from django.http.response import JsonResponse
from rest_framework.views import APIView
@ -29,9 +29,9 @@ class AssetActivityApi(DateRangeMixin, APIView):
def get_asset_login_metrics(self, queryset):
data = defaultdict(set)
for t, asset in queryset.values_list('date_start', 'asset'):
for t, _id in queryset.values_list('date_start', 'id'):
date_str = str(t.date())
data[date_str].add(asset)
data[date_str].add(_id)
metrics = [len(data.get(str(d), set())) for d in self.date_range_list]
return metrics
@ -47,35 +47,32 @@ class AssetActivityApi(DateRangeMixin, APIView):
stats = qs.aggregate(
total=Count(1),
asset_online=Count(1, filter=Q(is_finished=False)),
asset_count=Count('asset_id', distinct=True),
user_count=Count('user_id', distinct=True),
is_success_count=Count(1, filter=Q(is_success=True)),
)
asset_ids = {str(_id) for _id in qs.values_list('asset_id', flat=True).distinct()}
assets = Asset.objects.filter(id__in=asset_ids)
asset_login_by_protocol = group_stats(
qs, 'protocol_label', 'protocol'
qs, 'label', 'protocol'
)
asset_login_by_from = group_stats(
qs, 'login_from_label', 'login_from', LoginFrom.as_dict()
qs, 'label', 'login_from', LoginFrom.as_dict()
)
asset_by_type = group_stats(
assets, 'type', 'platform__type', all_type_dict,
assets, 'label', 'platform__type', all_type_dict,
)
dates_metrics_date = [date.strftime('%m-%d') for date in self.date_range_list] or ['0']
payload = {
**stats,
'session_stats': stats,
'asset_login_by_type': asset_by_type,
'asset_login_by_from': asset_login_by_from,
'asset_login_by_protocol': asset_login_by_protocol,
'asset_login_log_metrics': {
'dates_metrics_date': dates_metrics_date,
'dates_metrics_date': self.dates_metrics_date,
'dates_metrics_total': self.get_asset_login_metrics(qs),
}
}

View File

@ -1,22 +1,23 @@
# -*- coding: utf-8 -*-
#
from collections import defaultdict, OrderedDict
from django.db.models import Count, Q
from django.http import JsonResponse
from django.utils import timezone
from rest_framework.views import APIView
from assets.const import AllTypes, Connectivity, Category
from assets.const import AllTypes, Connectivity
from assets.models import Asset, Platform
from common.permissions import IsValidLicense
from common.utils import lazyproperty
from rbac.permissions import RBACPermission
from reports.api.assets.base import group_stats
from reports.mixins import DateRangeMixin
__all__ = ['AssetStatisticApi']
class AssetStatisticApi(APIView):
class AssetStatisticApi(DateRangeMixin, APIView):
http_method_names = ['get']
# TODO: Define the required RBAC permissions for this API
rbac_perms = {
@ -26,49 +27,60 @@ class AssetStatisticApi(APIView):
@lazyproperty
def base_qs(self):
return Asset.objects.only(
'id', 'platform', 'zone', 'connectivity', 'is_active'
)
return Asset.objects.all()
def get_added_asset_metrics(self):
filtered_queryset = self.filter_by_date_range(self.base_qs, 'date_created')
data = defaultdict(set)
for t, _id in filtered_queryset.values_list('date_created', 'id'):
date_str = str(t.date())
data[date_str].add(_id)
metrics = [len(data.get(str(d), set())) for d in self.date_range_list]
return metrics
def get(self, request, *args, **kwargs):
qs = self.base_qs
all_type_dict = dict(AllTypes.choices())
platform_by_type = group_stats(
Platform.objects.all(), 'type_label', 'type', all_type_dict,
)
stats = qs.aggregate(
total=Count(1),
active=Count(1, filter=Q(is_active=True)),
connected=Count(1, filter=Q(connectivity=Connectivity.OK)),
zone=Count(1, filter=Q(zone__isnull=False)),
directory_services=Count(1, filter=Q(directory_services__isnull=False)),
)
type_category_map = {
d['label']: str(d['category'].label)
for d in AllTypes.types()
}
by_type = group_stats(
qs, 'type', 'platform__type', all_type_dict,
)
by_category = group_stats(
qs, 'category', 'platform__category', Category.as_dict()
)
by_type_category = defaultdict(list)
for item in by_type:
category = type_category_map.get(item['label'], 'Other')
by_type_category[category].append(item)
by_zone = group_stats(
qs, 'zone_label', 'zone__name'
)
sorted_category_assets = OrderedDict()
desired_order = [str(i['label']) for i in AllTypes.categories()]
for category in desired_order:
sorted_category_assets[category] = by_type_category.get(category, [])
week_start = timezone.now() + timezone.timedelta(days=7)
assets_added_this_week_qs = qs.filter(date_created__gte=week_start)
assets_added_this_week_by_type = group_stats(
assets_added_this_week_qs, 'type', 'platform__type', all_type_dict,
)
stats.update({
'platform_count': Platform.objects.all().count(),
})
payload = {
**stats,
'platform_by_type': platform_by_type,
'assets_by_type': by_type,
'assets_by_category': by_category,
'assets_by_zone': by_zone,
'assets_added_this_week_count': assets_added_this_week_qs.count(),
'assets_added_this_week_by_type': assets_added_this_week_by_type,
'asset_stats': stats,
'assets_by_type_category': sorted_category_assets,
'added_asset_metrics': {
'dates_metrics_date': self.dates_metrics_date,
'dates_metrics_total': self.get_added_asset_metrics(),
}
}
return JsonResponse(payload, status=200)

View File

@ -59,7 +59,6 @@ class UserChangeSecretApi(DateRangeMixin, APIView):
def get(self, request, *args, **kwargs):
data = {}
dates_metrics_date = [date.strftime('%m-%d') for date in self.date_range_list] or ['0']
qs = self.filter_by_date_range(self.change_password_queryset, 'datetime')
@ -80,7 +79,7 @@ class UserChangeSecretApi(DateRangeMixin, APIView):
data['change_password_top10_change_bys'] = list(change_password_top10_change_bys)
data['user_change_password_metrics'] = {
'dates_metrics_date': dates_metrics_date,
'dates_metrics_date': self.dates_metrics_date,
'dates_metrics_total': self.get_change_password_metrics(qs),
}

View File

@ -89,18 +89,17 @@ class UserReportApi(DateRangeMixin, APIView):
def get(self, request, *args, **kwargs):
data = {}
dates_metrics_date = [date.strftime('%m-%d') for date in self.date_range_list] or ['0']
data['user_login_log_metrics'] = {
'dates_metrics_date': dates_metrics_date,
'dates_metrics_date': self.dates_metrics_date,
'dates_metrics_total': self.get_user_login_metrics(self.user_login_log_queryset),
}
data['user_login_failed_metrics'] = {
'dates_metrics_date': dates_metrics_date,
'dates_metrics_date': self.dates_metrics_date,
'dates_metrics_total': self.get_user_login_metrics(self.user_login_failed_queryset),
}
data['user_login_method_metrics'] = {
'dates_metrics_date': dates_metrics_date,
'dates_metrics_date': self.dates_metrics_date,
'dates_metrics_total': self.get_user_login_method_metrics(),
}
data['user_login_region_distribution'] = self.get_user_login_region_distribution()

View File

@ -40,3 +40,7 @@ class DateRangeMixin:
def filter_by_date_range(self, queryset, field_name: str):
start, end = self.date_range_bounds
return queryset.filter(**{f'{field_name}__range': (start, end)})
@lazyproperty
def dates_metrics_date(self):
return [date.strftime('%m-%d') for date in self.date_range_list] or ['0']