mirror of https://github.com/jumpserver/jumpserver
perf: add charts_map
parent
66f74f9c30
commit
060ef38169
|
@ -2,7 +2,7 @@
|
|||
#
|
||||
from collections import defaultdict
|
||||
|
||||
from django.db.models import Count
|
||||
from django.db.models import Count, Q
|
||||
from django.http.response import JsonResponse
|
||||
from rest_framework.views import APIView
|
||||
|
||||
|
@ -15,6 +15,9 @@ from reports.mixins import DateRangeMixin
|
|||
|
||||
__all__ = ['UserReportApi']
|
||||
|
||||
from users.models import User
|
||||
from users.models.user import Source
|
||||
|
||||
|
||||
class UserReportApi(DateRangeMixin, APIView):
|
||||
http_method_names = ['get']
|
||||
|
@ -87,16 +90,36 @@ class UserReportApi(DateRangeMixin, APIView):
|
|||
queryset = UserLoginLog.objects.filter(status=LoginStatusChoices.failed)
|
||||
return UserLoginLog.filter_queryset_by_org(queryset)
|
||||
|
||||
@lazyproperty
|
||||
def user_qs(self):
|
||||
return User.get_org_users()
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
data = {}
|
||||
|
||||
user_stats = self.user_qs.aggregate(
|
||||
total=Count(1),
|
||||
first_login=Count(1, filter=Q(is_first_login=True)),
|
||||
need_update_password=Count(1, filter=Q(need_update_password=True)),
|
||||
face_vector=Count(1, filter=Q(face_vector__isnull=False)),
|
||||
not_enabled_mfa=Count(1, filter=Q(mfa_level=0)),
|
||||
)
|
||||
|
||||
user_stats['valid'] = sum(1 for u in self.user_qs if u.is_valid)
|
||||
data['user_stats'] = user_stats
|
||||
|
||||
source_map = Source.as_dict()
|
||||
user_by_source = defaultdict(int)
|
||||
for source in self.user_qs.values_list('source', flat=True):
|
||||
k = source_map.get(source, source)
|
||||
user_by_source[str(k)] += 1
|
||||
|
||||
data['user_by_source'] = [{'name': k, 'value': v} for k, v in user_by_source.items()]
|
||||
|
||||
data['user_login_log_metrics'] = {
|
||||
'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': self.dates_metrics_date,
|
||||
'dates_metrics_total': self.get_user_login_metrics(self.user_login_failed_queryset),
|
||||
'dates_metrics_success_total': self.get_user_login_metrics(self.user_login_log_queryset),
|
||||
'dates_metrics_failure_total': self.get_user_login_metrics(self.user_login_failed_queryset),
|
||||
}
|
||||
data['user_login_method_metrics'] = {
|
||||
'dates_metrics_date': self.dates_metrics_date,
|
||||
|
|
|
@ -6,8 +6,7 @@ from urllib.parse import urlparse
|
|||
|
||||
from django.conf import settings
|
||||
from django.core.mail import EmailMultiAlternatives
|
||||
from django.http import FileResponse, HttpResponseBadRequest
|
||||
from django.http import JsonResponse
|
||||
from django.http import FileResponse, HttpResponseBadRequest, JsonResponse
|
||||
from django.utils import timezone
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.views import View
|
||||
|
@ -16,9 +15,21 @@ from pdf2image import convert_from_bytes
|
|||
from playwright.sync_api import sync_playwright
|
||||
|
||||
charts_map = {
|
||||
"UserActivity": {
|
||||
"title": "用户活动",
|
||||
"UserLoginActivity": {
|
||||
"title": "用户登录活动",
|
||||
"path": "/ui/#/reports/users/user-activity"
|
||||
},
|
||||
"UserPasswordChange": {
|
||||
"title": "用户改密记录",
|
||||
"path": "/ui/#/reports/users/change-password"
|
||||
},
|
||||
"AssetStatistics": {
|
||||
"title": "资产统计概览",
|
||||
"path": "/ui/#/reports/assets/asset-statistics"
|
||||
},
|
||||
"AssetAccessActivity": {
|
||||
"title": "资产访问活动",
|
||||
"path": "/ui/#/reports/assets/asset-activity"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,7 +92,7 @@ class ExportPdfView(View):
|
|||
sessionid = request.COOKIES.get(settings.SESSION_COOKIE_NAME)
|
||||
if not sessionid:
|
||||
return HttpResponseBadRequest('No sessionid found in cookies')
|
||||
|
||||
|
||||
pdf_bytes, title = export_chart_to_pdf(chart_name, sessionid, request=request)
|
||||
if not pdf_bytes:
|
||||
return HttpResponseBadRequest('Failed to generate PDF')
|
||||
|
|
|
@ -23,6 +23,10 @@ class Source(models.TextChoices):
|
|||
slack = "slack", _("Slack")
|
||||
custom = "custom", "Custom"
|
||||
|
||||
@classmethod
|
||||
def as_dict(cls):
|
||||
return {choice.value: choice.label for choice in cls}
|
||||
|
||||
|
||||
class SourceMixin:
|
||||
source: str
|
||||
|
|
Loading…
Reference in New Issue