From 0a9726d84540cea853970c7b204911fb4da5c204 Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Mon, 7 Aug 2023 15:50:09 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=B4=A6=E5=8F=B7=E5=A4=87=E4=BB=BD?= =?UTF-8?q?=E5=AF=86=E9=92=A5=E6=8B=86=E5=88=86=20(#11199)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: feng <1304903146@qq.com> --- .../automations/backup_account/handlers.py | 36 +++++++++-- .../0013_account_backup_recipients.py | 59 +++++++++++++++++++ .../models/automations/backup_account.py | 33 ++++++----- apps/accounts/serializers/account/backup.py | 6 +- 4 files changed, 109 insertions(+), 25 deletions(-) create mode 100644 apps/accounts/migrations/0013_account_backup_recipients.py diff --git a/apps/accounts/automations/backup_account/handlers.py b/apps/accounts/automations/backup_account/handlers.py index 7b087b101..e708e8d2d 100644 --- a/apps/accounts/automations/backup_account/handlers.py +++ b/apps/accounts/automations/backup_account/handlers.py @@ -71,8 +71,22 @@ class AssetAccountHandler(BaseAccountHandler): ) return filename + @staticmethod + def handler_secret(data, section): + for account_data in data: + secret = account_data.get('secret') + if not secret: + continue + length = len(secret) + index = length // 2 + if section == "front": + secret = secret[:index] + '*' * (length - index) + elif section == "back": + secret = '*' * (length - index) + secret[index:] + account_data['secret'] = secret + @classmethod - def create_data_map(cls, accounts): + def create_data_map(cls, accounts, section): data_map = defaultdict(list) if not accounts.exists(): @@ -92,6 +106,7 @@ class AssetAccountHandler(BaseAccountHandler): for tp, _accounts in account_type_map.items(): sheet_name = type_dict.get(tp, tp) data = AccountSecretSerializer(_accounts, many=True).data + cls.handler_secret(data, section) data_map.update(cls.add_rows(data, header_fields, sheet_name)) print('\n\033[33m- 共备份 {} 条账号\033[0m'.format(accounts.count())) @@ -104,7 +119,7 @@ class AccountBackupHandler: self.plan_name = self.execution.plan.name self.is_frozen = False # 任务状态冻结标志 - def create_excel(self): + def create_excel(self, section='complete'): print( '\n' '\033[32m>>> 正在生成资产或应用相关备份信息文件\033[0m' @@ -114,7 +129,7 @@ class AccountBackupHandler: time_start = time.time() files = [] accounts = self.execution.backup_accounts - data_map = AssetAccountHandler.create_data_map(accounts) + data_map = AssetAccountHandler.create_data_map(accounts, section) if not data_map: return files @@ -160,7 +175,8 @@ class AccountBackupHandler: self.execution.save() print('已完成对任务状态的更新') - def step_finished(self, is_success): + @staticmethod + def step_finished(is_success): if is_success: print('任务执行成功') else: @@ -170,14 +186,22 @@ class AccountBackupHandler: is_success = False error = '-' try: - recipients = self.execution.plan_snapshot.get('recipients') - if not recipients: + recipients_part_one = self.execution.snapshot.get('recipients_part_one', []) + recipients_part_two = self.execution.snapshot.get('recipients_part_two', []) + if not recipients_part_one and not recipients_part_two: print( '\n' '\033[32m>>> 该备份任务未分配收件人\033[0m' '' ) + if recipients_part_one and recipients_part_two: + files = self.create_excel(section='front') + self.send_backup_mail(files, recipients_part_one) + + files = self.create_excel(section='back') + self.send_backup_mail(files, recipients_part_two) else: + recipients = recipients_part_one or recipients_part_two files = self.create_excel() self.send_backup_mail(files, recipients) except Exception as e: diff --git a/apps/accounts/migrations/0013_account_backup_recipients.py b/apps/accounts/migrations/0013_account_backup_recipients.py new file mode 100644 index 000000000..ac9956b76 --- /dev/null +++ b/apps/accounts/migrations/0013_account_backup_recipients.py @@ -0,0 +1,59 @@ +# Generated by Django 4.1.10 on 2023-08-03 08:28 + +from django.conf import settings +from django.db import migrations, models + + +def migrate_recipients(apps, schema_editor): + account_backup_model = apps.get_model('accounts', 'AccountBackupAutomation') + execution_model = apps.get_model('accounts', 'AccountBackupExecution') + for account_backup in account_backup_model.objects.all(): + recipients = list(account_backup.recipients.all()) + if not recipients: + continue + account_backup.recipients_part_one.set(recipients) + + execution_bojs = [] + for execution in execution_model.objects.all(): + snapshot = execution.snapshot + recipients = snapshot.pop('recipients', {}) + snapshot.update({'recipients_part_one': recipients, 'recipients_part_two': {}}) + execution_bojs.append(execution) + execution_model.objects.bulk_update(execution_bojs, ['snapshot']) + + +class Migration(migrations.Migration): + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('accounts', '0012_auto_20230621_1456'), + ] + + operations = [ + migrations.AddField( + model_name='accountbackupautomation', + name='recipients_part_one', + field=models.ManyToManyField( + blank=True, related_name='recipient_part_one_plans', + to=settings.AUTH_USER_MODEL, verbose_name='Recipient part one' + ), + ), + migrations.AddField( + model_name='accountbackupautomation', + name='recipients_part_two', + field=models.ManyToManyField( + blank=True, related_name='recipient_part_two_plans', + to=settings.AUTH_USER_MODEL, verbose_name='Recipient part two' + ), + ), + migrations.RenameField( + model_name='accountbackupexecution', + old_name='plan_snapshot', + new_name='snapshot', + ), + migrations.RunPython(migrate_recipients), + migrations.RemoveField( + model_name='accountbackupautomation', + name='recipients', + ), + + ] diff --git a/apps/accounts/models/automations/backup_account.py b/apps/accounts/models/automations/backup_account.py index c72e0daef..c99c9e220 100644 --- a/apps/accounts/models/automations/backup_account.py +++ b/apps/accounts/models/automations/backup_account.py @@ -22,9 +22,13 @@ logger = get_logger(__file__) class AccountBackupAutomation(PeriodTaskModelMixin, JMSOrgBaseModel): types = models.JSONField(default=list) - recipients = models.ManyToManyField( - 'users.User', related_name='recipient_escape_route_plans', blank=True, - verbose_name=_("Recipient") + recipients_part_one = models.ManyToManyField( + 'users.User', related_name='recipient_part_one_plans', blank=True, + verbose_name=_("Recipient part one") + ) + recipients_part_two = models.ManyToManyField( + 'users.User', related_name='recipient_part_two_plans', blank=True, + verbose_name=_("Recipient part two") ) def __str__(self): @@ -52,9 +56,13 @@ class AccountBackupAutomation(PeriodTaskModelMixin, JMSOrgBaseModel): 'org_id': self.org_id, 'created_by': self.created_by, 'types': self.types, - 'recipients': { - str(recipient.id): (str(recipient), bool(recipient.secret_key)) - for recipient in self.recipients.all() + 'recipients_part_one': { + str(user.id): (str(user), bool(user.secret_key)) + for user in self.recipients_part_one.all() + }, + 'recipients_part_two': { + str(user.id): (str(user), bool(user.secret_key)) + for user in self.recipients_part_two.all() } } @@ -68,7 +76,7 @@ class AccountBackupAutomation(PeriodTaskModelMixin, JMSOrgBaseModel): except AttributeError: hid = str(uuid.uuid4()) execution = AccountBackupExecution.objects.create( - id=hid, plan=self, plan_snapshot=self.to_attr_json(), trigger=trigger + id=hid, plan=self, snapshot=self.to_attr_json(), trigger=trigger ) return execution.start() @@ -85,7 +93,7 @@ class AccountBackupExecution(OrgModelMixin): timedelta = models.FloatField( default=0.0, verbose_name=_('Time'), null=True ) - plan_snapshot = models.JSONField( + snapshot = models.JSONField( encoder=ModelJSONFieldEncoder, default=dict, blank=True, null=True, verbose_name=_('Account backup snapshot') ) @@ -108,16 +116,9 @@ class AccountBackupExecution(OrgModelMixin): @property def types(self): - types = self.plan_snapshot.get('types') + types = self.snapshot.get('types') return types - @property - def recipients(self): - recipients = self.plan_snapshot.get('recipients') - if not recipients: - return [] - return recipients.values() - @lazyproperty def backup_accounts(self): from accounts.models import Account diff --git a/apps/accounts/serializers/account/backup.py b/apps/accounts/serializers/account/backup.py index b6ec22203..f11861fa3 100644 --- a/apps/accounts/serializers/account/backup.py +++ b/apps/accounts/serializers/account/backup.py @@ -24,7 +24,7 @@ class AccountBackupSerializer(PeriodTaskSerializerMixin, BulkOrgResourceModelSer ] fields = read_only_fields + [ 'id', 'name', 'is_periodic', 'interval', 'crontab', - 'comment', 'recipients', 'types' + 'comment', 'types', 'recipients_part_one', 'recipients_part_two' ] extra_kwargs = { 'name': {'required': True}, @@ -44,7 +44,7 @@ class AccountBackupPlanExecutionSerializer(serializers.ModelSerializer): class Meta: model = AccountBackupExecution read_only_fields = [ - 'id', 'date_start', 'timedelta', 'plan_snapshot', - 'trigger', 'reason', 'is_success', 'org_id', 'recipients' + 'id', 'date_start', 'timedelta', 'snapshot', + 'trigger', 'reason', 'is_success', 'org_id' ] fields = read_only_fields + ['plan']