diff --git a/apps/accounts/api/account/account.py b/apps/accounts/api/account/account.py index 9fbf0ff0b..d3f1f4221 100644 --- a/apps/accounts/api/account/account.py +++ b/apps/accounts/api/account/account.py @@ -5,14 +5,16 @@ from rest_framework.response import Response from rest_framework.status import HTTP_200_OK from accounts import serializers +from accounts.const import ChangeSecretRecordStatusChoice from accounts.filters import AccountFilterSet from accounts.mixins import AccountRecordViewLogMixin -from accounts.models import Account +from accounts.models import Account, ChangeSecretRecord from assets.models import Asset, Node from authentication.permissions import UserConfirmation, ConfirmType from common.api.mixin import ExtraFilterFieldsMixin from common.drf.filters import AttrRulesFilterBackend from common.permissions import IsValidUser +from common.utils import lazyproperty from orgs.mixins.api import OrgBulkModelViewSet from rbac.permissions import RBACPermission @@ -127,17 +129,31 @@ class AccountHistoriesSecretAPI(ExtraFilterFieldsMixin, AccountRecordViewLogMixi 'GET': 'accounts.view_accountsecret', } - def get_object(self): + @lazyproperty + def account(self) -> Account: 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 def filter_spm_queryset(resource_ids, queryset): return queryset.filter(history_id__in=resource_ids) def get_queryset(self): - account = self.get_object() + account = self.account histories = account.history.all() - latest_history = account.history.first() + latest_history = self.latest_history if not latest_history: return histories if account.secret != latest_history.secret: @@ -146,3 +162,25 @@ class AccountHistoriesSecretAPI(ExtraFilterFieldsMixin, AccountRecordViewLogMixi return histories histories = histories.exclude(history_id=latest_history.history_id) 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 diff --git a/apps/accounts/migrations/0024_remove_changesecretrecord_date_started_and_more.py b/apps/accounts/migrations/0024_remove_changesecretrecord_date_started_and_more.py new file mode 100644 index 000000000..e7b1a928b --- /dev/null +++ b/apps/accounts/migrations/0024_remove_changesecretrecord_date_started_and_more.py @@ -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' + ), + ), + ] diff --git a/apps/accounts/models/automations/change_secret.py b/apps/accounts/models/automations/change_secret.py index a894f9d6d..c0efa829f 100644 --- a/apps/accounts/models/automations/change_secret.py +++ b/apps/accounts/models/automations/change_secret.py @@ -31,12 +31,20 @@ class ChangeSecretAutomation(ChangeSecretMixin, AccountBaseAutomation): class ChangeSecretRecord(JMSBaseModel): - execution = models.ForeignKey('accounts.AutomationExecution', on_delete=models.SET_NULL, null=True) - asset = models.ForeignKey('assets.Asset', on_delete=models.SET_NULL, null=True) - account = models.ForeignKey('accounts.Account', on_delete=models.SET_NULL, null=True) + account = models.ForeignKey( + 'accounts.Account', on_delete=models.SET_NULL, + 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')) 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) ignore_fail = models.BooleanField(default=False, verbose_name=_('Ignore fail')) status = models.CharField(