perf: Change secret record table dashboard

pull/14557/head
feng 2024-12-02 11:36:20 +08:00 committed by feng626
parent 49a811963c
commit 81daf33b16
4 changed files with 82 additions and 5 deletions

View File

@ -1,11 +1,12 @@
# -*- coding: utf-8 -*-
#
from django.db.models import Max, Q, Subquery, OuterRef
from rest_framework import status, mixins
from rest_framework.decorators import action
from rest_framework.response import Response
from accounts import serializers
from accounts.const import AutomationTypes
from accounts.const import AutomationTypes, ChangeSecretRecordStatusChoice
from accounts.filters import ChangeSecretRecordFilterSet
from accounts.models import ChangeSecretAutomation, ChangeSecretRecord
from accounts.tasks import execute_automation_record_task
@ -34,7 +35,8 @@ class ChangeSecretAutomationViewSet(OrgBulkModelViewSet):
class ChangeSecretRecordViewSet(mixins.ListModelMixin, OrgGenericViewSet):
filterset_class = ChangeSecretRecordFilterSet
search_fields = ('asset__address',)
search_fields = ('asset__address', 'account_username')
ordering_fields = ('date_finished',)
tp = AutomationTypes.change_secret
serializer_classes = {
'default': serializers.ChangeSecretRecordSerializer,
@ -43,6 +45,8 @@ class ChangeSecretRecordViewSet(mixins.ListModelMixin, OrgGenericViewSet):
rbac_perms = {
'execute': 'accounts.add_changesecretexecution',
'secret': 'accounts.view_changesecretrecord',
'dashboard': 'accounts.view_changesecretrecord',
'ignore_fail': 'accounts.view_changesecretrecord',
}
def get_permissions(self):
@ -53,9 +57,35 @@ class ChangeSecretRecordViewSet(mixins.ListModelMixin, OrgGenericViewSet):
]
return super().get_permissions()
def filter_queryset(self, queryset):
queryset = super().filter_queryset(queryset)
if self.action == 'dashboard':
return self.get_dashboard_queryset(queryset)
return queryset
@staticmethod
def get_dashboard_queryset(queryset):
recent_dates = queryset.values('account').annotate(
max_date_finished=Max('date_finished')
)
recent_success_accounts = queryset.filter(
account=OuterRef('account'),
date_finished=Subquery(
recent_dates.filter(account=OuterRef('account')).values('max_date_finished')[:1]
)
).filter(Q(status=ChangeSecretRecordStatusChoice.success) | Q(ignore_fail=True))
failed_records = queryset.filter(
~Q(account__in=Subquery(recent_success_accounts.values('account'))),
status=ChangeSecretRecordStatusChoice.failed
)
return failed_records
def get_queryset(self):
qs = ChangeSecretRecord.get_valid_records()
return qs.objects.filter(
return qs.filter(
execution__automation__type=self.tp
)
@ -78,6 +108,17 @@ class ChangeSecretRecordViewSet(mixins.ListModelMixin, OrgGenericViewSet):
serializer = self.get_serializer(instance)
return Response(serializer.data)
@action(methods=['get'], detail=False, url_path='dashboard')
def dashboard(self, request, *args, **kwargs):
return super().list(request, *args, **kwargs)
@action(methods=['patch'], detail=True, url_path='ignore-fail')
def ignore_fail(self, request, *args, **kwargs):
instance = self.get_object()
instance.ignore_fail = True
instance.save(update_fields=['ignore_fail'])
return Response(status=status.HTTP_200_OK)
class ChangSecretExecutionViewSet(AutomationExecutionViewSet):
rbac_perms = (

View File

@ -6,6 +6,7 @@ from django_filters import rest_framework as drf_filters
from assets.models import Node
from common.drf.filters import BaseFilterSet
from common.utils.timezone import local_zero_hour, local_now
from .models import Account, GatheredAccount, ChangeSecretRecord
@ -28,7 +29,7 @@ class AccountFilterSet(BaseFilterSet):
latest_updated = drf_filters.BooleanFilter(method='filter_latest')
latest_secret_changed = drf_filters.BooleanFilter(method='filter_latest')
latest_secret_change_failed = drf_filters.BooleanFilter(method='filter_latest')
risk = drf_filters.CharFilter(method='filter_risk',)
risk = drf_filters.CharFilter(method='filter_risk', )
long_time_no_change_secret = drf_filters.BooleanFilter(method='filter_long_time')
long_time_no_verified = drf_filters.BooleanFilter(method='filter_long_time')
@ -127,6 +128,17 @@ class ChangeSecretRecordFilterSet(BaseFilterSet):
account_username = drf_filters.CharFilter(field_name='account__username', lookup_expr='icontains')
execution_id = drf_filters.CharFilter(field_name='execution_id', lookup_expr='exact')
days = drf_filters.NumberFilter(method='filter_days')
@staticmethod
def filter_days(queryset, name, value):
value = int(value)
dt = local_zero_hour()
if value != 1:
dt = local_now() - timezone.timedelta(days=value)
return queryset.filter(date_finished__gte=dt)
class Meta:
model = ChangeSecretRecord
fields = ['id', 'status', 'asset_id', 'execution']

View File

@ -0,0 +1,23 @@
# Generated by Django 4.1.13 on 2024-12-02 03:21
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('accounts', '0017_serviceintegration'),
]
operations = [
migrations.AddField(
model_name='changesecretrecord',
name='ignore_fail',
field=models.BooleanField(default=False, verbose_name='Ignore fail'),
),
migrations.AlterField(
model_name='changesecretrecord',
name='date_finished',
field=models.DateTimeField(blank=True, db_index=True, null=True, verbose_name='Date finished'),
),
]

View File

@ -37,7 +37,8 @@ class ChangeSecretRecord(JMSBaseModel):
old_secret = fields.EncryptTextField(blank=True, null=True, verbose_name=_('Old secret'))
new_secret = fields.EncryptTextField(blank=True, null=True, verbose_name=_('New secret'))
date_started = models.DateTimeField(blank=True, null=True, verbose_name=_('Date started'))
date_finished = models.DateTimeField(blank=True, null=True, verbose_name=_('Date finished'))
date_finished = models.DateTimeField(blank=True, null=True, verbose_name=_('Date finished'), db_index=True)
ignore_fail = models.BooleanField(default=False, verbose_name=_('Ignore fail'))
status = models.CharField(
max_length=16, verbose_name=_('Status'), default=ChangeSecretRecordStatusChoice.pending.value
)