mirror of https://github.com/jumpserver/jumpserver
perf: add charts_map
parent
66f74f9c30
commit
060ef38169
|
@ -2,7 +2,7 @@
|
||||||
#
|
#
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
from django.db.models import Count
|
from django.db.models import Count, Q
|
||||||
from django.http.response import JsonResponse
|
from django.http.response import JsonResponse
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
|
|
||||||
|
@ -15,6 +15,9 @@ from reports.mixins import DateRangeMixin
|
||||||
|
|
||||||
__all__ = ['UserReportApi']
|
__all__ = ['UserReportApi']
|
||||||
|
|
||||||
|
from users.models import User
|
||||||
|
from users.models.user import Source
|
||||||
|
|
||||||
|
|
||||||
class UserReportApi(DateRangeMixin, APIView):
|
class UserReportApi(DateRangeMixin, APIView):
|
||||||
http_method_names = ['get']
|
http_method_names = ['get']
|
||||||
|
@ -87,16 +90,36 @@ class UserReportApi(DateRangeMixin, APIView):
|
||||||
queryset = UserLoginLog.objects.filter(status=LoginStatusChoices.failed)
|
queryset = UserLoginLog.objects.filter(status=LoginStatusChoices.failed)
|
||||||
return UserLoginLog.filter_queryset_by_org(queryset)
|
return UserLoginLog.filter_queryset_by_org(queryset)
|
||||||
|
|
||||||
|
@lazyproperty
|
||||||
|
def user_qs(self):
|
||||||
|
return User.get_org_users()
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
data = {}
|
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'] = {
|
data['user_login_log_metrics'] = {
|
||||||
'dates_metrics_date': self.dates_metrics_date,
|
'dates_metrics_date': self.dates_metrics_date,
|
||||||
'dates_metrics_total': self.get_user_login_metrics(self.user_login_log_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_failed_metrics'] = {
|
|
||||||
'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'] = {
|
data['user_login_method_metrics'] = {
|
||||||
'dates_metrics_date': self.dates_metrics_date,
|
'dates_metrics_date': self.dates_metrics_date,
|
||||||
|
|
|
@ -6,8 +6,7 @@ from urllib.parse import urlparse
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.mail import EmailMultiAlternatives
|
from django.core.mail import EmailMultiAlternatives
|
||||||
from django.http import FileResponse, HttpResponseBadRequest
|
from django.http import FileResponse, HttpResponseBadRequest, JsonResponse
|
||||||
from django.http import JsonResponse
|
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
from django.views import View
|
from django.views import View
|
||||||
|
@ -16,9 +15,21 @@ from pdf2image import convert_from_bytes
|
||||||
from playwright.sync_api import sync_playwright
|
from playwright.sync_api import sync_playwright
|
||||||
|
|
||||||
charts_map = {
|
charts_map = {
|
||||||
"UserActivity": {
|
"UserLoginActivity": {
|
||||||
"title": "用户活动",
|
"title": "用户登录活动",
|
||||||
"path": "/ui/#/reports/users/user-activity"
|
"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)
|
sessionid = request.COOKIES.get(settings.SESSION_COOKIE_NAME)
|
||||||
if not sessionid:
|
if not sessionid:
|
||||||
return HttpResponseBadRequest('No sessionid found in cookies')
|
return HttpResponseBadRequest('No sessionid found in cookies')
|
||||||
|
|
||||||
pdf_bytes, title = export_chart_to_pdf(chart_name, sessionid, request=request)
|
pdf_bytes, title = export_chart_to_pdf(chart_name, sessionid, request=request)
|
||||||
if not pdf_bytes:
|
if not pdf_bytes:
|
||||||
return HttpResponseBadRequest('Failed to generate PDF')
|
return HttpResponseBadRequest('Failed to generate PDF')
|
||||||
|
|
|
@ -23,6 +23,10 @@ class Source(models.TextChoices):
|
||||||
slack = "slack", _("Slack")
|
slack = "slack", _("Slack")
|
||||||
custom = "custom", "Custom"
|
custom = "custom", "Custom"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def as_dict(cls):
|
||||||
|
return {choice.value: choice.label for choice in cls}
|
||||||
|
|
||||||
|
|
||||||
class SourceMixin:
|
class SourceMixin:
|
||||||
source: str
|
source: str
|
||||||
|
|
Loading…
Reference in New Issue