mirror of https://github.com/jumpserver/jumpserver
feat: 修改模版账号密码 同步更新关联的账号 (#10328)
* feat: 修改模版账号密码 同步更新关联的账号 * feat: 同步多个账号 --------- Co-authored-by: feng <1304903146@qq.com>pull/10333/head
parent
9d2ae7d1ed
commit
917620736b
|
@ -5,7 +5,6 @@ from django_filters import rest_framework as drf_filters
|
||||||
|
|
||||||
from assets.models import Node
|
from assets.models import Node
|
||||||
from common.drf.filters import BaseFilterSet
|
from common.drf.filters import BaseFilterSet
|
||||||
|
|
||||||
from .models import Account, GatheredAccount
|
from .models import Account, GatheredAccount
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,7 +45,7 @@ class AccountFilterSet(BaseFilterSet):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Account
|
model = Account
|
||||||
fields = ['id', 'asset_id']
|
fields = ['id', 'asset_id', 'source_id']
|
||||||
|
|
||||||
|
|
||||||
class GatheredAccountFilterSet(BaseFilterSet):
|
class GatheredAccountFilterSet(BaseFilterSet):
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.db.models import Count
|
||||||
|
from django.utils import timezone
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from simple_history.models import HistoricalRecords
|
from simple_history.models import HistoricalRecords
|
||||||
|
|
||||||
|
@ -118,3 +120,45 @@ class AccountTemplate(BaseAccount):
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.username
|
return self.username
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def bulk_update_accounts(accounts, data):
|
||||||
|
history_model = Account.history.model
|
||||||
|
account_ids = accounts.values_list('id', flat=True)
|
||||||
|
history_accounts = history_model.objects.filter(id__in=account_ids)
|
||||||
|
account_id_count_map = {
|
||||||
|
str(i['id']): i['count']
|
||||||
|
for i in history_accounts.values('id').order_by('id')
|
||||||
|
.annotate(count=Count(1)).values('id', 'count')
|
||||||
|
}
|
||||||
|
|
||||||
|
for account in accounts:
|
||||||
|
account_id = str(account.id)
|
||||||
|
account.version = account_id_count_map.get(account_id) + 1
|
||||||
|
for k, v in data.items():
|
||||||
|
setattr(account, k, v)
|
||||||
|
Account.objects.bulk_update(accounts, ['version', 'secret'])
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def bulk_create_history_accounts(accounts, user_id):
|
||||||
|
history_model = Account.history.model
|
||||||
|
history_account_objs = []
|
||||||
|
for account in accounts:
|
||||||
|
history_account_objs.append(
|
||||||
|
history_model(
|
||||||
|
id=account.id,
|
||||||
|
version=account.version,
|
||||||
|
secret=account.secret,
|
||||||
|
secret_type=account.secret_type,
|
||||||
|
history_user_id=user_id,
|
||||||
|
history_date=timezone.now()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
history_model.objects.bulk_create(history_account_objs)
|
||||||
|
|
||||||
|
def bulk_sync_account_secret(self, accounts, user_id):
|
||||||
|
""" 批量同步账号密码 """
|
||||||
|
if not accounts:
|
||||||
|
return
|
||||||
|
self.bulk_update_accounts(accounts, {'secret': self.secret})
|
||||||
|
self.bulk_create_history_accounts(accounts, user_id)
|
||||||
|
|
|
@ -1,86 +1,37 @@
|
||||||
from django.db.transaction import atomic
|
from rest_framework import serializers
|
||||||
from django.db.utils import IntegrityError
|
|
||||||
|
|
||||||
from accounts.models import AccountTemplate, Account
|
from accounts.models import AccountTemplate, Account
|
||||||
from assets.models import Asset
|
|
||||||
from common.serializers import SecretReadableMixin
|
from common.serializers import SecretReadableMixin
|
||||||
from .base import BaseAccountSerializer
|
from .base import BaseAccountSerializer
|
||||||
|
|
||||||
|
|
||||||
class AccountTemplateSerializer(BaseAccountSerializer):
|
class AccountTemplateSerializer(BaseAccountSerializer):
|
||||||
|
is_sync_account = serializers.BooleanField(default=False, write_only=True)
|
||||||
|
_is_sync_account = False
|
||||||
|
|
||||||
class Meta(BaseAccountSerializer.Meta):
|
class Meta(BaseAccountSerializer.Meta):
|
||||||
model = AccountTemplate
|
model = AccountTemplate
|
||||||
|
fields = BaseAccountSerializer.Meta.fields + ['is_sync_account']
|
||||||
|
|
||||||
@staticmethod
|
def sync_accounts_secret(self, instance, diff):
|
||||||
def account_save(data, account):
|
if not self._is_sync_account or 'secret' not in diff:
|
||||||
for field, value in data.items():
|
|
||||||
setattr(account, field, value)
|
|
||||||
try:
|
|
||||||
account.save(update_fields=list(data.keys()))
|
|
||||||
except IntegrityError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# TODO 数据库访问的太多了 后期优化
|
|
||||||
@atomic()
|
|
||||||
def bulk_update_accounts(self, instance, diff):
|
|
||||||
accounts = Account.objects.filter(source_id=instance.id)
|
|
||||||
if not accounts:
|
|
||||||
return
|
return
|
||||||
|
|
||||||
diff.pop('secret', None)
|
accounts = Account.objects.filter(source_id=instance.id)
|
||||||
name = diff.pop('name', None)
|
instance.bulk_sync_account_secret(accounts, self.context['request'].user.id)
|
||||||
username = diff.pop('username', None)
|
|
||||||
secret_type = diff.pop('secret_type', None)
|
|
||||||
update_accounts = []
|
|
||||||
for account in accounts:
|
|
||||||
for field, value in diff.items():
|
|
||||||
setattr(account, field, value)
|
|
||||||
update_accounts.append(account)
|
|
||||||
|
|
||||||
if update_accounts:
|
def validate(self, attrs):
|
||||||
Account.objects.bulk_update(update_accounts, diff.keys())
|
self._is_sync_account = attrs.pop('is_sync_account', None)
|
||||||
|
attrs = super().validate(attrs)
|
||||||
if name:
|
return attrs
|
||||||
for account in accounts:
|
|
||||||
data = {'name': name}
|
|
||||||
self.account_save(data, account)
|
|
||||||
|
|
||||||
if secret_type and username:
|
|
||||||
asset_ids_supports = self.get_asset_ids_supports(accounts, secret_type)
|
|
||||||
for account in accounts:
|
|
||||||
asset_id = account.asset_id
|
|
||||||
if asset_id not in asset_ids_supports:
|
|
||||||
data = {'username': username}
|
|
||||||
self.account_save(data, account)
|
|
||||||
continue
|
|
||||||
data = {'username': username, 'secret_type': secret_type, 'secret': instance.secret}
|
|
||||||
self.account_save(data, account)
|
|
||||||
elif secret_type:
|
|
||||||
asset_ids_supports = self.get_asset_ids_supports(accounts, secret_type)
|
|
||||||
for account in accounts:
|
|
||||||
asset_id = account.asset_id
|
|
||||||
if asset_id not in asset_ids_supports:
|
|
||||||
continue
|
|
||||||
data = {'secret_type': secret_type, 'secret': instance.secret}
|
|
||||||
self.account_save(data, account)
|
|
||||||
elif username:
|
|
||||||
for account in accounts:
|
|
||||||
data = {'username': username}
|
|
||||||
self.account_save(data, account)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_asset_ids_supports(accounts, secret_type):
|
|
||||||
asset_ids = accounts.values_list('asset_id', flat=True)
|
|
||||||
secret_type_supports = Asset.get_secret_type_assets(asset_ids, secret_type)
|
|
||||||
return [asset.id for asset in secret_type_supports]
|
|
||||||
|
|
||||||
def update(self, instance, validated_data):
|
def update(self, instance, validated_data):
|
||||||
# diff = {
|
diff = {
|
||||||
# k: v for k, v in validated_data.items()
|
k: v for k, v in validated_data.items()
|
||||||
# if getattr(instance, k) != v
|
if getattr(instance, k) != v
|
||||||
# }
|
}
|
||||||
instance = super().update(instance, validated_data)
|
instance = super().update(instance, validated_data)
|
||||||
# self.bulk_update_accounts(instance, diff)
|
self.sync_accounts_secret(instance, diff)
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue