mirror of https://github.com/jumpserver/jumpserver
perf: Display account history in combination with password change records
parent
8420c0b22b
commit
95ff9a3cdb
|
@ -5,14 +5,16 @@ from rest_framework.response import Response
|
||||||
from rest_framework.status import HTTP_200_OK
|
from rest_framework.status import HTTP_200_OK
|
||||||
|
|
||||||
from accounts import serializers
|
from accounts import serializers
|
||||||
|
from accounts.const import ChangeSecretRecordStatusChoice
|
||||||
from accounts.filters import AccountFilterSet
|
from accounts.filters import AccountFilterSet
|
||||||
from accounts.mixins import AccountRecordViewLogMixin
|
from accounts.mixins import AccountRecordViewLogMixin
|
||||||
from accounts.models import Account
|
from accounts.models import Account, ChangeSecretRecord
|
||||||
from assets.models import Asset, Node
|
from assets.models import Asset, Node
|
||||||
from authentication.permissions import UserConfirmation, ConfirmType
|
from authentication.permissions import UserConfirmation, ConfirmType
|
||||||
from common.api.mixin import ExtraFilterFieldsMixin
|
from common.api.mixin import ExtraFilterFieldsMixin
|
||||||
from common.drf.filters import AttrRulesFilterBackend
|
from common.drf.filters import AttrRulesFilterBackend
|
||||||
from common.permissions import IsValidUser
|
from common.permissions import IsValidUser
|
||||||
|
from common.utils import lazyproperty
|
||||||
from orgs.mixins.api import OrgBulkModelViewSet
|
from orgs.mixins.api import OrgBulkModelViewSet
|
||||||
from rbac.permissions import RBACPermission
|
from rbac.permissions import RBACPermission
|
||||||
|
|
||||||
|
@ -127,17 +129,31 @@ class AccountHistoriesSecretAPI(ExtraFilterFieldsMixin, AccountRecordViewLogMixi
|
||||||
'GET': 'accounts.view_accountsecret',
|
'GET': 'accounts.view_accountsecret',
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_object(self):
|
@lazyproperty
|
||||||
|
def account(self) -> Account:
|
||||||
return get_object_or_404(Account, pk=self.kwargs.get('pk'))
|
return get_object_or_404(Account, pk=self.kwargs.get('pk'))
|
||||||
|
|
||||||
|
def get_object(self):
|
||||||
|
return self.account
|
||||||
|
|
||||||
|
@lazyproperty
|
||||||
|
def latest_history(self):
|
||||||
|
return self.account.history.first()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def latest_change_secret_record(self) -> ChangeSecretRecord:
|
||||||
|
return self.account.change_secret_records.filter(
|
||||||
|
status=ChangeSecretRecordStatusChoice.pending
|
||||||
|
).order_by('-date_created').first()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def filter_spm_queryset(resource_ids, queryset):
|
def filter_spm_queryset(resource_ids, queryset):
|
||||||
return queryset.filter(history_id__in=resource_ids)
|
return queryset.filter(history_id__in=resource_ids)
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
account = self.get_object()
|
account = self.account
|
||||||
histories = account.history.all()
|
histories = account.history.all()
|
||||||
latest_history = account.history.first()
|
latest_history = self.latest_history
|
||||||
if not latest_history:
|
if not latest_history:
|
||||||
return histories
|
return histories
|
||||||
if account.secret != latest_history.secret:
|
if account.secret != latest_history.secret:
|
||||||
|
@ -146,3 +162,25 @@ class AccountHistoriesSecretAPI(ExtraFilterFieldsMixin, AccountRecordViewLogMixi
|
||||||
return histories
|
return histories
|
||||||
histories = histories.exclude(history_id=latest_history.history_id)
|
histories = histories.exclude(history_id=latest_history.history_id)
|
||||||
return histories
|
return histories
|
||||||
|
|
||||||
|
def filter_queryset(self, queryset):
|
||||||
|
queryset = super().filter_queryset(queryset)
|
||||||
|
queryset = list(queryset)
|
||||||
|
latest_history = self.latest_history
|
||||||
|
if not latest_history:
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
latest_change_secret_record = self.latest_change_secret_record
|
||||||
|
if not latest_change_secret_record:
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
if latest_change_secret_record.date_created > latest_history.history_date:
|
||||||
|
temp_history = self.model(
|
||||||
|
secret=latest_change_secret_record.new_secret,
|
||||||
|
secret_type=self.account.secret_type,
|
||||||
|
version=latest_history.version,
|
||||||
|
history_date=latest_change_secret_record.date_created,
|
||||||
|
)
|
||||||
|
queryset = [temp_history] + queryset
|
||||||
|
|
||||||
|
return queryset
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
# Generated by Django 4.1.13 on 2024-12-24 05:27
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
('assets', '0011_auto_20241204_1516'),
|
||||||
|
('accounts', '0023_alter_changesecretrecord_options'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='changesecretrecord',
|
||||||
|
name='date_started',
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='changesecretrecord',
|
||||||
|
name='account',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
null=True, on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
related_name='change_secret_records', to='accounts.account'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='changesecretrecord',
|
||||||
|
name='asset',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
null=True, on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
related_name='asset_change_secret_records', to='assets.asset'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='changesecretrecord',
|
||||||
|
name='execution',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
null=True, on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
related_name='execution_change_secret_records', to='accounts.automationexecution'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
|
@ -31,12 +31,20 @@ class ChangeSecretAutomation(ChangeSecretMixin, AccountBaseAutomation):
|
||||||
|
|
||||||
|
|
||||||
class ChangeSecretRecord(JMSBaseModel):
|
class ChangeSecretRecord(JMSBaseModel):
|
||||||
execution = models.ForeignKey('accounts.AutomationExecution', on_delete=models.SET_NULL, null=True)
|
account = models.ForeignKey(
|
||||||
asset = models.ForeignKey('assets.Asset', on_delete=models.SET_NULL, null=True)
|
'accounts.Account', on_delete=models.SET_NULL,
|
||||||
account = models.ForeignKey('accounts.Account', on_delete=models.SET_NULL, null=True)
|
null=True, related_name='change_secret_records'
|
||||||
|
)
|
||||||
|
asset = models.ForeignKey(
|
||||||
|
'assets.Asset', on_delete=models.SET_NULL,
|
||||||
|
null=True, related_name='asset_change_secret_records'
|
||||||
|
)
|
||||||
|
execution = models.ForeignKey(
|
||||||
|
'accounts.AutomationExecution', on_delete=models.SET_NULL,
|
||||||
|
null=True, related_name='execution_change_secret_records',
|
||||||
|
)
|
||||||
old_secret = fields.EncryptTextField(blank=True, null=True, verbose_name=_('Old secret'))
|
old_secret = fields.EncryptTextField(blank=True, null=True, verbose_name=_('Old secret'))
|
||||||
new_secret = fields.EncryptTextField(blank=True, null=True, verbose_name=_('New 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'), db_index=True)
|
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'))
|
ignore_fail = models.BooleanField(default=False, verbose_name=_('Ignore fail'))
|
||||||
status = models.CharField(
|
status = models.CharField(
|
||||||
|
|
Loading…
Reference in New Issue