perf: merge with remote

pull/14774/head^2
ibuler 2025-01-03 11:23:42 +08:00
commit 738465c02d
21 changed files with 6783 additions and 6607 deletions

View File

@ -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
@ -35,6 +37,8 @@ class AccountViewSet(OrgBulkModelViewSet):
'partial_update': ['accounts.change_account'], 'partial_update': ['accounts.change_account'],
'su_from_accounts': 'accounts.view_account', 'su_from_accounts': 'accounts.view_account',
'clear_secret': 'accounts.change_account', 'clear_secret': 'accounts.change_account',
'move_to_assets': 'accounts.create_account',
'copy_to_assets': 'accounts.create_account',
} }
export_as_zip = True export_as_zip = True
@ -88,6 +92,43 @@ class AccountViewSet(OrgBulkModelViewSet):
self.model.objects.filter(id__in=account_ids).update(secret=None) self.model.objects.filter(id__in=account_ids).update(secret=None)
return Response(status=HTTP_200_OK) return Response(status=HTTP_200_OK)
def _copy_or_move_to_assets(self, request, move=False):
account = self.get_object()
asset_ids = request.data.get('assets', [])
assets = Asset.objects.filter(id__in=asset_ids)
field_names = [
'name', 'username', 'secret_type', 'secret',
'privileged', 'is_active', 'source', 'source_id', 'comment'
]
account_data = {field: getattr(account, field) for field in field_names}
creation_results = {}
success_count = 0
for asset in assets:
account_data['asset'] = asset
creation_results[asset] = {'state': 'created'}
try:
self.model.objects.create(**account_data)
success_count += 1
except Exception as e:
creation_results[asset] = {'error': str(e), 'state': 'error'}
results = [{'asset': str(asset), **res} for asset, res in creation_results.items()]
if move and success_count > 0:
account.delete()
return Response(results, status=HTTP_200_OK)
@action(methods=['post'], detail=True, url_path='move-to-assets')
def move_to_assets(self, request, *args, **kwargs):
return self._copy_or_move_to_assets(request, move=True)
@action(methods=['post'], detail=True, url_path='copy-to-assets')
def copy_to_assets(self, request, *args, **kwargs):
return self._copy_or_move_to_assets(request, move=False)
class AccountSecretsViewSet(AccountRecordViewLogMixin, AccountViewSet): class AccountSecretsViewSet(AccountRecordViewLogMixin, AccountViewSet):
""" """
@ -127,17 +168,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 +201,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

View File

@ -9,9 +9,10 @@ from rest_framework.response import Response
from accounts import serializers from accounts import serializers
from accounts.const import AutomationTypes from accounts.const import AutomationTypes
from accounts.filters import GatheredAccountFilterSet from accounts.filters import GatheredAccountFilterSet
from accounts.models import GatherAccountsAutomation, AutomationExecution from accounts.models import GatherAccountsAutomation, AutomationExecution, Account
from accounts.models import GatheredAccount from accounts.models import GatheredAccount
from assets.models import Asset from assets.models import Asset
from common.utils.http import is_true
from orgs.mixins.api import OrgBulkModelViewSet from orgs.mixins.api import OrgBulkModelViewSet
from .base import AutomationExecutionViewSet from .base import AutomationExecutionViewSet
@ -80,30 +81,39 @@ class GatheredAccountViewSet(OrgBulkModelViewSet):
"details": serializers.GatheredAccountDetailsSerializer "details": serializers.GatheredAccountDetailsSerializer
} }
rbac_perms = { rbac_perms = {
"sync_accounts": "assets.add_gatheredaccount",
"status": "assets.change_gatheredaccount", "status": "assets.change_gatheredaccount",
"details": "assets.view_gatheredaccount" "details": "assets.view_gatheredaccount"
} }
@action(methods=["put"], detail=True, url_path="status") @action(methods=["put"], detail=False, url_path="status")
def status(self, request, *args, **kwargs): def status(self, request, *args, **kwargs):
instance = self.get_object() ids = request.data.get('ids', [])
instance.status = request.data.get("status") new_status = request.data.get("status")
instance.save(update_fields=["status"]) updated_instances = GatheredAccount.objects.filter(id__in=ids)
updated_instances.update(status=new_status)
if instance.status == "confirmed": if new_status == "confirmed":
GatheredAccount.sync_accounts([instance]) GatheredAccount.sync_accounts(updated_instances)
return Response(status=status.HTTP_200_OK) return Response(status=status.HTTP_200_OK)
@action(methods=["post"], detail=False, url_path="delete-remote") def perform_destroy(self, instance):
def delete_remote(self, request, *args, **kwargs): request = self.request
asset_id = request.data.get("asset_id") params = request.query_params
username = request.data.get("username") is_delete_remote = params.get("is_delete_remote")
is_delete_account = params.get("is_delete_account")
asset_id = params.get("asset")
username = params.get("username")
if is_true(is_delete_remote):
self._delete_remote(asset_id, username)
if is_true(is_delete_account):
account = get_object_or_404(Account, username=username, asset_id=asset_id)
account.delete()
super().perform_destroy(instance)
def _delete_remote(self, asset_id, username):
asset = get_object_or_404(Asset, pk=asset_id) asset = get_object_or_404(Asset, pk=asset_id)
handler = RiskHandler(asset, username, request=self.request) handler = RiskHandler(asset, username, request=self.request)
handler.handle_delete_remote() handler.handle_delete_remote()
return Response(status=status.HTTP_200_OK)
@action(methods=["get"], detail=True, url_path="details") @action(methods=["get"], detail=True, url_path="details")
def details(self, request, *args, **kwargs): def details(self, request, *args, **kwargs):

View File

@ -33,7 +33,8 @@ class GatherAccountsFilter:
@staticmethod @staticmethod
def mysql_filter(info): def mysql_filter(info):
result = {} result = {}
for username, user_info in info.items(): for host, user_dict in info.items():
for username, user_info in user_dict.items():
password_last_changed = parse_date(user_info.get('password_last_changed')) password_last_changed = parse_date(user_info.get('password_last_changed'))
password_lifetime = user_info.get('password_lifetime') password_lifetime = user_info.get('password_lifetime')
user = { user = {
@ -59,7 +60,7 @@ class GatherAccountsFilter:
'groups': '', 'groups': '',
} }
detail = { detail = {
'canlogin': user_info.get('canlogin'), 'can_login': user_info.get('canlogin'),
'superuser': user_info.get('superuser'), 'superuser': user_info.get('superuser'),
} }
user['detail'] = detail user['detail'] = detail
@ -87,7 +88,6 @@ class GatherAccountsFilter:
'is_disabled': user_info.get('is_disabled', ''), 'is_disabled': user_info.get('is_disabled', ''),
'default_database_name': user_info.get('default_database_name', ''), 'default_database_name': user_info.get('default_database_name', ''),
} }
print(user)
user['detail'] = detail user['detail'] = detail
result[user['username']] = user result[user['username']] = user
return result return result

View File

@ -16,7 +16,7 @@ DEFAULT_PASSWORD_RULES = {
__all__ = [ __all__ = [
'AutomationTypes', 'SecretStrategy', 'SSHKeyStrategy', 'Connectivity', 'AutomationTypes', 'SecretStrategy', 'SSHKeyStrategy', 'Connectivity',
'DEFAULT_PASSWORD_LENGTH', 'DEFAULT_PASSWORD_RULES', 'TriggerChoice', 'DEFAULT_PASSWORD_LENGTH', 'DEFAULT_PASSWORD_RULES', 'TriggerChoice',
'PushAccountActionChoice', 'AccountBackupType', 'ChangeSecretRecordStatusChoice', 'PushAccountActionChoice', 'AccountBackupType', 'ChangeSecretRecordStatusChoice', 'GatherAccountDetailField'
] ]
@ -114,3 +114,20 @@ class ChangeSecretRecordStatusChoice(models.TextChoices):
failed = 'failed', _('Failed') failed = 'failed', _('Failed')
success = 'success', _('Success') success = 'success', _('Success')
pending = 'pending', _('Pending') pending = 'pending', _('Pending')
class GatherAccountDetailField(models.TextChoices):
can_login = 'can_login', _('Can login')
superuser = 'superuser', _('Superuser')
create_date = 'create_date', _('Create date')
is_disabled = 'is_disabled', _('Is disabled')
default_database_name = 'default_database_name', _('Default database name')
uid = 'uid', _('UID')
account_status = 'account_status', _('Account status')
default_tablespace = 'default_tablespace', _('Default tablespace')
roles = 'roles', _('Roles')
privileges = 'privileges', _('Privileges')
groups = 'groups', _('Groups')
sudoers = 'sudoers', 'sudoers'
authorized_keys = 'authorized_keys', _('Authorized keys')
db = 'db', _('DB')

View File

@ -1,13 +1,14 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
from django.db.models import Q, F from django.db.models import Q, F, Value, CharField
from django.db.models.functions import Concat
from django.utils import timezone from django.utils import timezone
from django_filters import rest_framework as drf_filters 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 common.utils.timezone import local_zero_hour, local_now from common.utils.timezone import local_zero_hour, local_now
from .models import Account, GatheredAccount, ChangeSecretRecord from .models import Account, GatheredAccount, ChangeSecretRecord, AccountRisk
class AccountFilterSet(BaseFilterSet): class AccountFilterSet(BaseFilterSet):
@ -70,11 +71,20 @@ class AccountFilterSet(BaseFilterSet):
if not value: if not value:
return queryset return queryset
queryset = ( asset_usernames = AccountRisk.objects.filter(risk=value). \
queryset.prefetch_related("risks") values_list(
.annotate(risk=F("risks__risk"), confirmed=F("risks__confirmed")) Concat(
.filter(risk=value, confirmed=False) F('asset_id'), Value('-'), F('username'),
output_field=CharField()
), flat=True
) )
queryset = queryset.annotate(
asset_username=Concat(
F('asset_id'), Value('-'), F('username'),
output_field=CharField()
)
).filter(asset_username__in=asset_usernames)
return queryset return queryset
@staticmethod @staticmethod

View File

@ -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'
),
),
]

View File

@ -3,12 +3,14 @@ from django.utils.translation import gettext_lazy as _
from simple_history.models import HistoricalRecords from simple_history.models import HistoricalRecords
from assets.models.base import AbsConnectivity from assets.models.base import AbsConnectivity
from common.utils import lazyproperty from common.utils import lazyproperty, get_logger
from labels.mixins import LabeledMixin from labels.mixins import LabeledMixin
from .base import BaseAccount from .base import BaseAccount
from .mixins import VaultModelMixin from .mixins import VaultModelMixin
from ..const import Source from ..const import Source
logger = get_logger(__file__)
__all__ = ['Account', 'AccountHistoricalRecords'] __all__ = ['Account', 'AccountHistoricalRecords']
@ -26,7 +28,7 @@ class AccountHistoricalRecords(HistoricalRecords):
history_account = instance.history.first() history_account = instance.history.first()
if history_account is None: if history_account is None:
self.updated_version = 1 self.updated_version = 0
return super().post_save(instance, created, using=using, **kwargs) return super().post_save(instance, created, using=using, **kwargs)
history_attrs = {field: getattr(history_account, field) for field in check_fields} history_attrs = {field: getattr(history_account, field) for field in check_fields}
@ -38,12 +40,13 @@ class AccountHistoricalRecords(HistoricalRecords):
if not diff: if not diff:
return return
self.updated_version = history_account.version + 1 self.updated_version = history_account.version + 1
instance.version = self.updated_version
return super().post_save(instance, created, using=using, **kwargs) return super().post_save(instance, created, using=using, **kwargs)
def create_historical_record(self, instance, history_type, using=None): def create_historical_record(self, instance, history_type, using=None):
super().create_historical_record(instance, history_type, using=using) super().create_historical_record(instance, history_type, using=using)
if self.updated_version is not None: # Ignore deletion history_type: -
instance.version = self.updated_version if self.updated_version is not None and history_type != '-':
instance.save(update_fields=['version']) instance.save(update_fields=['version'])
def create_history_model(self, model, inherited): def create_history_model(self, model, inherited):

View File

@ -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(

View File

@ -2,7 +2,7 @@ from django.shortcuts import get_object_or_404
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from rest_framework import serializers from rest_framework import serializers
from accounts.const import AutomationTypes from accounts.const import AutomationTypes, GatherAccountDetailField
from accounts.models import GatherAccountsAutomation from accounts.models import GatherAccountsAutomation
from accounts.models import GatheredAccount from accounts.models import GatheredAccount
from accounts.serializers.account.account import AccountAssetSerializer as _AccountAssetSerializer from accounts.serializers.account.account import AccountAssetSerializer as _AccountAssetSerializer
@ -82,7 +82,9 @@ class GatheredAccountDetailsSerializer(serializers.Serializer):
obj = get_object_or_404(GatheredAccount, pk=pk) obj = get_object_or_404(GatheredAccount, pk=pk)
details = obj.detail details = obj.detail
for key, value in details.items(): for key, value in details.items():
field_dict = GatherAccountDetailField._member_map_
label = field_dict[key].label if key in field_dict else key
if isinstance(value, bool): if isinstance(value, bool):
self.fields[key] = serializers.BooleanField(label=key, read_only=True) self.fields[key] = serializers.BooleanField(label=label, read_only=True)
else: else:
self.fields[key] = serializers.CharField(label=key, read_only=True) self.fields[key] = serializers.CharField(label=label, read_only=True)

View File

@ -6,9 +6,7 @@ from django.utils import timezone
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from assets.const import Connectivity from assets.const import Connectivity
from common.utils import ( from common.utils import get_logger
get_logger
)
logger = get_logger(__file__) logger = get_logger(__file__)

View File

@ -230,7 +230,7 @@ class AssetSerializer(BulkOrgResourceModelSerializer, ResourceLabelsMixin, Writa
.prefetch_related('platform', 'platform__automation') \ .prefetch_related('platform', 'platform__automation') \
.annotate(category=F("platform__category")) \ .annotate(category=F("platform__category")) \
.annotate(type=F("platform__type")) \ .annotate(type=F("platform__type")) \
.annotate(assets_amount=Count('accounts')) .annotate(accounts_amount=Count('accounts'))
if queryset.model is Asset: if queryset.model is Asset:
queryset = queryset.prefetch_related('labels__label', 'labels') queryset = queryset.prefetch_related('labels__label', 'labels')
else: else:

View File

@ -6,7 +6,8 @@ from rest_framework.validators import UniqueValidator
from assets.models import Asset from assets.models import Asset
from common.serializers import ( from common.serializers import (
WritableNestedModelSerializer, type_field_map, MethodSerializer, WritableNestedModelSerializer, type_field_map, MethodSerializer,
DictSerializer, create_serializer_class, ResourceLabelsMixin DictSerializer, create_serializer_class, ResourceLabelsMixin,
CommonSerializerMixin
) )
from common.serializers.fields import LabeledChoiceField, ObjectRelatedField from common.serializers.fields import LabeledChoiceField, ObjectRelatedField
from common.utils import lazyproperty from common.utils import lazyproperty
@ -158,7 +159,7 @@ class PlatformCustomField(serializers.Serializer):
choices = serializers.ListField(default=list, label=_("Choices"), required=False) choices = serializers.ListField(default=list, label=_("Choices"), required=False)
class PlatformSerializer(ResourceLabelsMixin, WritableNestedModelSerializer): class PlatformSerializer(ResourceLabelsMixin, CommonSerializerMixin, WritableNestedModelSerializer):
id = serializers.IntegerField( id = serializers.IntegerField(
label='ID', required=False, label='ID', required=False,
validators=[UniqueValidator(queryset=Platform.objects.all())] validators=[UniqueValidator(queryset=Platform.objects.all())]

View File

@ -5254,7 +5254,7 @@ msgstr ""
#: ops/models/job.py:148 #: ops/models/job.py:148
msgid "Timeout (Seconds)" msgid "Timeout (Seconds)"
msgstr "" msgstr "Timeout (Sec)"
#: ops/models/job.py:153 #: ops/models/job.py:153
msgid "Use Parameter Define" msgid "Use Parameter Define"
@ -5334,8 +5334,8 @@ msgid "Next execution time"
msgstr "" msgstr ""
#: ops/serializers/job.py:15 #: ops/serializers/job.py:15
msgid "Execute after saving" msgid "Run on save"
msgstr "Execute after saving" msgstr "Run on save"
#: ops/serializers/job.py:72 #: ops/serializers/job.py:72
msgid "Job type" msgid "Job type"

View File

@ -5527,7 +5527,7 @@ msgid "Next execution time"
msgstr "最後の実行" msgstr "最後の実行"
#: ops/serializers/job.py:15 #: ops/serializers/job.py:15
msgid "Execute after saving" msgid "Run on save"
msgstr "保存後に実行" msgstr "保存後に実行"
#: ops/serializers/job.py:72 #: ops/serializers/job.py:72

View File

@ -5478,7 +5478,7 @@ msgid "Next execution time"
msgstr "下次执行时间" msgstr "下次执行时间"
#: ops/serializers/job.py:15 #: ops/serializers/job.py:15
msgid "Execute after saving" msgid "Run on save"
msgstr "保存后执行" msgstr "保存后执行"
#: ops/serializers/job.py:72 #: ops/serializers/job.py:72

View File

@ -8,9 +8,8 @@
"AccessIP": "IP whitelist", "AccessIP": "IP whitelist",
"AccessKey": "Access key", "AccessKey": "Access key",
"Account": "Account", "Account": "Account",
"AccountAmount": "Account amount",
"AccountSessions": "Sessions",
"AccountActivity": "Activity", "AccountActivity": "Activity",
"AccountAmount": "Account amount",
"AccountBackup": "Backup accounts", "AccountBackup": "Backup accounts",
"AccountBackupCreate": "Create account backup", "AccountBackupCreate": "Create account backup",
"AccountBackupDetail": "Backup account details", "AccountBackupDetail": "Backup account details",
@ -19,12 +18,12 @@
"AccountChangeSecret": "Change account secret", "AccountChangeSecret": "Change account secret",
"AccountChangeSecretDetail": "Change account secret details", "AccountChangeSecretDetail": "Change account secret details",
"AccountDeleteConfirmMsg": "Delete account, continue?", "AccountDeleteConfirmMsg": "Delete account, continue?",
"AccountExportTips": "The exported information contains sensitive information such as encrypted account numbers. the exported format is an encrypted zip file (if you have not set the encryption password, please go to personal info to set the file encryption password).",
"AccountDiscoverDetail": "Gather account details", "AccountDiscoverDetail": "Gather account details",
"AccountDiscoverList": "Discover accounts", "AccountDiscoverList": "Discover accounts",
"AccountDiscoverTaskCreate": "Create discover accounts task", "AccountDiscoverTaskCreate": "Create discover accounts task",
"AccountDiscoverTaskList": "Discover accounts tasks", "AccountDiscoverTaskList": "Discover accounts tasks",
"AccountDiscoverTaskUpdate": "Update the discover accounts task", "AccountDiscoverTaskUpdate": "Update the discover accounts task",
"AccountExportTips": "The exported information contains sensitive information such as encrypted account numbers. the exported format is an encrypted zip file (if you have not set the encryption password, please go to personal info to set the file encryption password).",
"AccountList": "Accounts", "AccountList": "Accounts",
"AccountPolicy": "Account policy", "AccountPolicy": "Account policy",
"AccountPolicyHelpText": "For accounts that do not meet the requirements when creating, such as: non-compliant key types and unique key constraints, you can choose the above strategy.", "AccountPolicyHelpText": "For accounts that do not meet the requirements when creating, such as: non-compliant key types and unique key constraints, you can choose the above strategy.",
@ -32,6 +31,7 @@
"AccountPushDetail": "Push account details", "AccountPushDetail": "Push account details",
"AccountPushList": "Push accounts", "AccountPushList": "Push accounts",
"AccountPushUpdate": "Update push account", "AccountPushUpdate": "Update push account",
"AccountSessions": "Sessions",
"AccountStorage": "Account storage", "AccountStorage": "Account storage",
"AccountTemplate": "Account templates", "AccountTemplate": "Account templates",
"AccountTemplateList": "Account templates", "AccountTemplateList": "Account templates",
@ -255,11 +255,11 @@
"Certificate": "Certificate", "Certificate": "Certificate",
"CertificateKey": "Client key", "CertificateKey": "Client key",
"ChangeCredentials": "Change account secrets", "ChangeCredentials": "Change account secrets",
"ChangeSecret": "Change secrets",
"ChangeCredentialsHelpText": "The secret is the password or key used to connect to the asset. when the secret is changed, the asset will be updated with the new secret", "ChangeCredentialsHelpText": "The secret is the password or key used to connect to the asset. when the secret is changed, the asset will be updated with the new secret",
"ChangeField": "Change field", "ChangeField": "Change field",
"ChangeOrganization": "Change organization", "ChangeOrganization": "Change organization",
"ChangePassword": "Change password", "ChangePassword": "Change password",
"ChangeSecret": "Change secrets",
"ChangeSecretParams": "Change secret parameters", "ChangeSecretParams": "Change secret parameters",
"ChangeViewHelpText": "Click to switch different views", "ChangeViewHelpText": "Click to switch different views",
"Chat": "Chat", "Chat": "Chat",
@ -392,6 +392,7 @@
"DangerCommand": "Dangerous command", "DangerCommand": "Dangerous command",
"DangerousCommandNum": "Total dangerous commands", "DangerousCommandNum": "Total dangerous commands",
"Dashboard": "Dashboard", "Dashboard": "Dashboard",
"DataLastUsed": "Last used",
"Database": "Database", "Database": "Database",
"DatabaseCreate": "Create asset - database", "DatabaseCreate": "Create asset - database",
"DatabasePort": "Database protocol port", "DatabasePort": "Database protocol port",
@ -408,7 +409,6 @@
"DateLastLogin": "Last login date", "DateLastLogin": "Last login date",
"DateLastMonth": "Last month", "DateLastMonth": "Last month",
"DateLastSync": "Last sync", "DateLastSync": "Last sync",
"DataLastUsed": "Last used",
"DateLastWeek": "Last week", "DateLastWeek": "Last week",
"DateLastYear": "Last year", "DateLastYear": "Last year",
"DatePasswordLastUpdated": "Last password update date", "DatePasswordLastUpdated": "Last password update date",
@ -436,6 +436,9 @@
"DestinationIP": "Destination address", "DestinationIP": "Destination address",
"DestinationPort": "Destination port", "DestinationPort": "Destination port",
"Detail": "Detail", "Detail": "Detail",
"DetectEngines": "Detect engines",
"DetectResults": "Detect results",
"DetectTasks": "Detect tasks",
"DeviceCreate": "Create asset - device", "DeviceCreate": "Create asset - device",
"DeviceUpdate": "Update the asset - device", "DeviceUpdate": "Update the asset - device",
"Digit": "Number", "Digit": "Number",
@ -445,6 +448,9 @@
"Disable": "Disable", "Disable": "Disable",
"DisableSelected": "Disable selected", "DisableSelected": "Disable selected",
"DisableSuccessMsg": "Successfully disabled", "DisableSuccessMsg": "Successfully disabled",
"DiscoverAccounts": "Discover accounts",
"DiscoverAccountsHelpText": "Collect account information on assets. the collected account information can be imported into the system for centralized management.",
"DiscoveredAccountList": "Discovered accounts",
"DisplayName": "Name", "DisplayName": "Name",
"Docs": "Docs", "Docs": "Docs",
"Download": "Download", "Download": "Download",
@ -552,9 +558,6 @@
"GatewayList": "Gateways", "GatewayList": "Gateways",
"GatewayPlatformHelpText": "Only platforms with names starting with Gateway can be used as gateways.", "GatewayPlatformHelpText": "Only platforms with names starting with Gateway can be used as gateways.",
"GatewayUpdate": "Update the gateway", "GatewayUpdate": "Update the gateway",
"DiscoverAccounts": "Discover accounts",
"DiscoverAccountsHelpText": "Collect account information on assets. the collected account information can be imported into the system for centralized management.",
"DiscoveredAccountList": "Discovered accounts",
"General": "General", "General": "General",
"GeneralAccounts": "General accounts", "GeneralAccounts": "General accounts",
"GeneralSetting": "General", "GeneralSetting": "General",
@ -1004,6 +1007,7 @@
"Retry": "Retry", "Retry": "Retry",
"RetrySelected": "Retry selected", "RetrySelected": "Retry selected",
"Reviewer": "Approvers", "Reviewer": "Approvers",
"RiskDetection": "Risk detection",
"Role": "Role", "Role": "Role",
"RoleCreate": "Create role", "RoleCreate": "Create role",
"RoleDetail": "Role details", "RoleDetail": "Role details",
@ -1218,13 +1222,10 @@
"Task": "Task", "Task": "Task",
"TaskDetail": "Task details", "TaskDetail": "Task details",
"TaskDone": "Task finished", "TaskDone": "Task finished",
"RiskDetection": "Risk detection",
"DetectTasks": "Detect tasks",
"DetectResults": "Detect results",
"DetectEngines": "Detect engines",
"TaskID": "Task id", "TaskID": "Task id",
"TaskList": "Tasks", "TaskList": "Tasks",
"TaskMonitor": "Monitoring", "TaskMonitor": "Monitoring",
"TaskPath": "Task path",
"TechnologyConsult": "Technical consultation", "TechnologyConsult": "Technical consultation",
"TempPasswordTip": "The temporary password is valid for 300 seconds and becomes invalid immediately after use", "TempPasswordTip": "The temporary password is valid for 300 seconds and becomes invalid immediately after use",
"TempToken": "Temporary tokens", "TempToken": "Temporary tokens",
@ -1406,6 +1407,5 @@
"ZoneUpdate": "Update the zone", "ZoneUpdate": "Update the zone",
"disallowSelfUpdateFields": "Not allowed to modify the current fields yourself", "disallowSelfUpdateFields": "Not allowed to modify the current fields yourself",
"forceEnableMFAHelpText": "If force enable, user can not disable by themselves", "forceEnableMFAHelpText": "If force enable, user can not disable by themselves",
"removeWarningMsg": "Are you sure you want to remove", "removeWarningMsg": "Are you sure you want to remove"
"TaskPath": "Task path"
} }

View File

@ -17,12 +17,12 @@
"AccountChangeSecret": "アカウントパスワード変更", "AccountChangeSecret": "アカウントパスワード変更",
"AccountChangeSecretDetail": "アカウントのパスワード変更詳細", "AccountChangeSecretDetail": "アカウントのパスワード変更詳細",
"AccountDeleteConfirmMsg": "アカウントを削除しますか?続行しますか?", "AccountDeleteConfirmMsg": "アカウントを削除しますか?続行しますか?",
"AccountExportTips": "エクスポートする情報には口座の暗号文が含まれ、これは機密情報に関連しています。エクスポートする形式は、暗号化されたzipファイルです暗号化パスワードを設定していない場合は、個人情報でファイルの暗号化パスワードを設定してください。",
"AccountDiscoverDetail": "アカウント収集詳細", "AccountDiscoverDetail": "アカウント収集詳細",
"AccountDiscoverList": "アカウントの収集", "AccountDiscoverList": "アカウントの収集",
"AccountDiscoverTaskCreate": "アカウント収集タスクの作成", "AccountDiscoverTaskCreate": "アカウント収集タスクの作成",
"AccountDiscoverTaskList": "アカウント収集タスク", "AccountDiscoverTaskList": "アカウント収集タスク",
"AccountDiscoverTaskUpdate": "アカウント収集タスクを更新", "AccountDiscoverTaskUpdate": "アカウント収集タスクを更新",
"AccountExportTips": "エクスポートする情報には口座の暗号文が含まれ、これは機密情報に関連しています。エクスポートする形式は、暗号化されたzipファイルです暗号化パスワードを設定していない場合は、個人情報でファイルの暗号化パスワードを設定してください。",
"AccountList": "クラウドアカウント", "AccountList": "クラウドアカウント",
"AccountPolicy": "アカウントポリシー", "AccountPolicy": "アカウントポリシー",
"AccountPolicyHelpText": "作成時に要件を満たさないアカウント,例えば:キータイプが規格外,一意キー制約,上記の方針を選択できます。", "AccountPolicyHelpText": "作成時に要件を満たさないアカウント,例えば:キータイプが規格外,一意キー制約,上記の方針を選択できます。",
@ -404,6 +404,7 @@
"DangerCommand": "危険なコマンド", "DangerCommand": "危険なコマンド",
"DangerousCommandNum": "危険なコマンド数", "DangerousCommandNum": "危険なコマンド数",
"Dashboard": "ダッシュボード", "Dashboard": "ダッシュボード",
"DataLastUsed": "さいごしようび",
"Database": "データベース", "Database": "データベース",
"DatabaseCreate": "資産-データベースの作成", "DatabaseCreate": "資産-データベースの作成",
"DatabasePort": "データベースプロトコルポート", "DatabasePort": "データベースプロトコルポート",
@ -420,7 +421,6 @@
"DateLastLogin": "最後にログインした日", "DateLastLogin": "最後にログインした日",
"DateLastMonth": "最近一ヶ月", "DateLastMonth": "最近一ヶ月",
"DateLastSync": "最終同期日", "DateLastSync": "最終同期日",
"DataLastUsed": "さいごしようび",
"DateLastWeek": "最新の一週間", "DateLastWeek": "最新の一週間",
"DateLastYear": "最近一年", "DateLastYear": "最近一年",
"DatePasswordLastUpdated": "最終パスワード更新日", "DatePasswordLastUpdated": "最終パスワード更新日",
@ -457,6 +457,9 @@
"Disable": "無効化", "Disable": "無効化",
"DisableSelected": "選択を無効にする", "DisableSelected": "選択を無効にする",
"DisableSuccessMsg": "無効化成功", "DisableSuccessMsg": "無効化成功",
"DiscoverAccounts": "アカウント収集",
"DiscoverAccountsHelpText": "資産上のアカウント情報を収集します。収集したアカウント情報は、システムにインポートして一元管理が可能です",
"DiscoveredAccountList": "収集したアカウント",
"DisplayName": "名前", "DisplayName": "名前",
"Docs": "文書", "Docs": "文書",
"Download": "ダウンロード", "Download": "ダウンロード",
@ -564,9 +567,6 @@
"GatewayList": "ゲートウェイリスト", "GatewayList": "ゲートウェイリスト",
"GatewayPlatformHelpText": "ゲートウェイプラットフォームは、Gatewayで始まるプラットフォームのみ選択可能です。", "GatewayPlatformHelpText": "ゲートウェイプラットフォームは、Gatewayで始まるプラットフォームのみ選択可能です。",
"GatewayUpdate": "ゲートウェイの更新", "GatewayUpdate": "ゲートウェイの更新",
"DiscoverAccounts": "アカウント収集",
"DiscoverAccountsHelpText": "資産上のアカウント情報を収集します。収集したアカウント情報は、システムにインポートして一元管理が可能です",
"DiscoveredAccountList": "収集したアカウント",
"General": "基本", "General": "基本",
"GeneralAccounts": "一般アカウント", "GeneralAccounts": "一般アカウント",
"GeneralSetting": "汎用設定", "GeneralSetting": "汎用設定",

View File

@ -7,6 +7,7 @@
"Accept": "同意", "Accept": "同意",
"AccessIP": "IP 白名单", "AccessIP": "IP 白名单",
"AccessKey": "访问密钥", "AccessKey": "访问密钥",
"Account": "账号",
"AccountAmount": "账号数量", "AccountAmount": "账号数量",
"AccountBackup": "账号备份", "AccountBackup": "账号备份",
"AccountBackupCreate": "创建账号备份", "AccountBackupCreate": "创建账号备份",
@ -16,13 +17,12 @@
"AccountChangeSecret": "账号改密", "AccountChangeSecret": "账号改密",
"AccountChangeSecretDetail": "账号改密详情", "AccountChangeSecretDetail": "账号改密详情",
"AccountDeleteConfirmMsg": "删除账号,是否继续?", "AccountDeleteConfirmMsg": "删除账号,是否继续?",
"AccountExportTips": "导出信息中包含账号密文涉及敏感信息导出的格式为一个加密的zip文件若没有设置加密密码请前往个人信息中设置文件加密密码。",
"AccountDiscoverDetail": "账号发现详情", "AccountDiscoverDetail": "账号发现详情",
"AccountDiscoverList": "账号发现", "AccountDiscoverList": "账号发现",
"AccountDiscoverTaskCreate": "创建账号发现任务", "AccountDiscoverTaskCreate": "创建账号发现任务",
"AccountDiscoverTaskList": "账号发现任务", "AccountDiscoverTaskList": "账号发现任务",
"AccountDiscoverTaskUpdate": "更新账号发现任务", "AccountDiscoverTaskUpdate": "更新账号发现任务",
"Account": "账号", "AccountExportTips": "导出信息中包含账号密文涉及敏感信息导出的格式为一个加密的zip文件若没有设置加密密码请前往个人信息中设置文件加密密码",
"AccountList": "账号列表", "AccountList": "账号列表",
"AccountPolicy": "账号策略", "AccountPolicy": "账号策略",
"AccountPolicyHelpText": "创建时对于不符合要求的账号,如:密钥类型不合规,唯一键约束,可选择以上策略。", "AccountPolicyHelpText": "创建时对于不符合要求的账号,如:密钥类型不合规,唯一键约束,可选择以上策略。",
@ -389,6 +389,7 @@
"DangerCommand": "危险命令", "DangerCommand": "危险命令",
"DangerousCommandNum": "危险命令数", "DangerousCommandNum": "危险命令数",
"Dashboard": "仪表盘", "Dashboard": "仪表盘",
"DataLastUsed": "最后使用日期",
"Database": "数据库", "Database": "数据库",
"DatabaseCreate": "创建资产-数据库", "DatabaseCreate": "创建资产-数据库",
"DatabasePort": "数据库协议端口", "DatabasePort": "数据库协议端口",
@ -405,7 +406,6 @@
"DateLastLogin": "最后登录日期", "DateLastLogin": "最后登录日期",
"DateLastMonth": "最近一月", "DateLastMonth": "最近一月",
"DateLastSync": "最后同步日期", "DateLastSync": "最后同步日期",
"DataLastUsed": "最后使用日期",
"DateLastWeek": "最近一周", "DateLastWeek": "最近一周",
"DateLastYear": "最近一年", "DateLastYear": "最近一年",
"DatePasswordLastUpdated": "最后更新密码日期", "DatePasswordLastUpdated": "最后更新密码日期",
@ -442,6 +442,9 @@
"Disable": "禁用", "Disable": "禁用",
"DisableSelected": "禁用所选", "DisableSelected": "禁用所选",
"DisableSuccessMsg": "禁用成功", "DisableSuccessMsg": "禁用成功",
"DiscoverAccounts": "账号发现",
"DiscoverAccountsHelpText": "收集资产上的账号信息。收集后的账号信息可以导入到系统中,方便统一管理",
"DiscoveredAccountList": "发现的账号",
"DisplayName": "名称", "DisplayName": "名称",
"Docs": "文档", "Docs": "文档",
"Download": "下载", "Download": "下载",
@ -549,9 +552,6 @@
"GatewayList": "网关列表", "GatewayList": "网关列表",
"GatewayPlatformHelpText": "网关平台只能选择以 Gateway 开头的平台", "GatewayPlatformHelpText": "网关平台只能选择以 Gateway 开头的平台",
"GatewayUpdate": "更新网关", "GatewayUpdate": "更新网关",
"DiscoverAccounts": "账号发现",
"DiscoverAccountsHelpText": "收集资产上的账号信息。收集后的账号信息可以导入到系统中,方便统一管理",
"DiscoveredAccountList": "发现的账号",
"General": "基本", "General": "基本",
"GeneralAccounts": "普通账号", "GeneralAccounts": "普通账号",
"GeneralSetting": "通用配置", "GeneralSetting": "通用配置",
@ -623,6 +623,7 @@
"InstanceAddress": "实例地址", "InstanceAddress": "实例地址",
"InstanceName": "实例名称", "InstanceName": "实例名称",
"InstancePlatformName": "实例平台名称", "InstancePlatformName": "实例平台名称",
"IntegrationApplication": "服务对接",
"Interface": "网络接口", "Interface": "网络接口",
"InterfaceSettings": "界面设置", "InterfaceSettings": "界面设置",
"Interval": "间隔", "Interval": "间隔",
@ -1089,7 +1090,6 @@
"ServerAccountKey": "服务账号密钥", "ServerAccountKey": "服务账号密钥",
"ServerError": "服务器错误", "ServerError": "服务器错误",
"ServerTime": "服务器时间", "ServerTime": "服务器时间",
"IntegrationApplication": "服务对接",
"Session": "会话", "Session": "会话",
"SessionCommands": "会话命令", "SessionCommands": "会话命令",
"SessionConnectTrend": "会话连接趋势", "SessionConnectTrend": "会话连接趋势",
@ -1222,6 +1222,7 @@
"TaskID": "任务 ID", "TaskID": "任务 ID",
"TaskList": "任务列表", "TaskList": "任务列表",
"TaskMonitor": "任务监控", "TaskMonitor": "任务监控",
"TaskPath": "任务路径",
"TechnologyConsult": "技术咨询", "TechnologyConsult": "技术咨询",
"TempPasswordTip": "临时密码有效期为 300 秒,使用后立刻失效", "TempPasswordTip": "临时密码有效期为 300 秒,使用后立刻失效",
"TempToken": "临时密码", "TempToken": "临时密码",
@ -1403,6 +1404,5 @@
"ZoneUpdate": "更新网域", "ZoneUpdate": "更新网域",
"disallowSelfUpdateFields": "不允许自己修改当前字段", "disallowSelfUpdateFields": "不允许自己修改当前字段",
"forceEnableMFAHelpText": "如果强制启用,用户无法自行禁用", "forceEnableMFAHelpText": "如果强制启用,用户无法自行禁用",
"removeWarningMsg": "你确定要移除", "removeWarningMsg": "你确定要移除"
"TaskPath": "任务路径"
} }

View File

@ -17,13 +17,13 @@
"AccountChangeSecret": "帳號改密", "AccountChangeSecret": "帳號改密",
"AccountChangeSecretDetail": "帳號變更密碼詳情", "AccountChangeSecretDetail": "帳號變更密碼詳情",
"AccountDeleteConfirmMsg": "刪除帳號,是否繼續?", "AccountDeleteConfirmMsg": "刪除帳號,是否繼續?",
"AccountExportTips": "導出信息中包含賬號密文涉及敏感信息導出的格式為一個加密的zip文件若沒有設置加密密碼請前往個人信息中設置文件加密密碼。",
"AccountDiscoverDetail": "帳號收集詳情", "AccountDiscoverDetail": "帳號收集詳情",
"AccountDiscoverList": "帳號收集", "AccountDiscoverList": "帳號收集",
"AccountDiscoverTaskCreate": "創建賬號收集任務", "AccountDiscoverTaskCreate": "創建賬號收集任務",
"AccountDiscoverTaskExecutionList": "任務執行列表", "AccountDiscoverTaskExecutionList": "任務執行列表",
"AccountDiscoverTaskList": "賬號收集任務", "AccountDiscoverTaskList": "賬號收集任務",
"AccountDiscoverTaskUpdate": "更新賬號收集任務", "AccountDiscoverTaskUpdate": "更新賬號收集任務",
"AccountExportTips": "導出信息中包含賬號密文涉及敏感信息導出的格式為一個加密的zip文件若沒有設置加密密碼請前往個人信息中設置文件加密密碼。",
"AccountHelpText": "雲帳號是用來連接雲服務商的帳號,用於獲取雲服務商的資源資訊", "AccountHelpText": "雲帳號是用來連接雲服務商的帳號,用於獲取雲服務商的資源資訊",
"AccountHistoryHelpMessage": "記錄當前帳號的歷史版本", "AccountHistoryHelpMessage": "記錄當前帳號的歷史版本",
"AccountList": "雲帳號", "AccountList": "雲帳號",
@ -508,6 +508,7 @@
"DangerCommand": "危險命令", "DangerCommand": "危險命令",
"DangerousCommandNum": "危險命令數", "DangerousCommandNum": "危險命令數",
"Dashboard": "儀錶盤", "Dashboard": "儀錶盤",
"DataLastUsed": "最後使用日期",
"Database": "資料庫", "Database": "資料庫",
"DatabaseApp": "資料庫", "DatabaseApp": "資料庫",
"DatabaseAppCount": "資料庫應用數量", "DatabaseAppCount": "資料庫應用數量",
@ -536,7 +537,6 @@
"DateLastMonth": "最近一月", "DateLastMonth": "最近一月",
"DateLastRun": "上次運行日期", "DateLastRun": "上次運行日期",
"DateLastSync": "最後同步日期", "DateLastSync": "最後同步日期",
"DataLastUsed": "最後使用日期",
"DateLastWeek": "最近一週", "DateLastWeek": "最近一週",
"DateLastYear": "最近一年", "DateLastYear": "最近一年",
"DatePasswordLastUpdated": "最後更新密碼日期", "DatePasswordLastUpdated": "最後更新密碼日期",
@ -584,6 +584,9 @@
"DisableSuccessMsg": "禁用成功", "DisableSuccessMsg": "禁用成功",
"DisabledAsset": "禁用的", "DisabledAsset": "禁用的",
"DisabledUser": "禁用的", "DisabledUser": "禁用的",
"DiscoverAccounts": "帳號收集",
"DiscoverAccountsHelpText": "收集資產上的賬號資訊。收集後的賬號資訊可以導入到系統中,方便統一",
"DiscoveredAccountList": "Collected accounts",
"Disk": "硬碟", "Disk": "硬碟",
"DisplayName": "名稱", "DisplayName": "名稱",
"Docs": "文件", "Docs": "文件",
@ -720,9 +723,6 @@
"GatewayPlatformHelpText": "網關平台只能選擇以 Gateway 開頭的平台", "GatewayPlatformHelpText": "網關平台只能選擇以 Gateway 開頭的平台",
"GatewayProtocolHelpText": "SSH網關支持代理SSH,RDP和VNC", "GatewayProtocolHelpText": "SSH網關支持代理SSH,RDP和VNC",
"GatewayUpdate": "更新網關", "GatewayUpdate": "更新網關",
"DiscoverAccounts": "帳號收集",
"DiscoverAccountsHelpText": "收集資產上的賬號資訊。收集後的賬號資訊可以導入到系統中,方便統一",
"DiscoveredAccountList": "Collected accounts",
"General": "基本", "General": "基本",
"GeneralAccounts": "普通帳號", "GeneralAccounts": "普通帳號",
"GeneralSetting": "General Settings", "GeneralSetting": "General Settings",

View File

@ -12,7 +12,7 @@ from orgs.mixins.serializers import BulkOrgResourceModelSerializer
class JobSerializer(BulkOrgResourceModelSerializer, PeriodTaskSerializerMixin): class JobSerializer(BulkOrgResourceModelSerializer, PeriodTaskSerializerMixin):
creator = ReadableHiddenField(default=serializers.CurrentUserDefault()) creator = ReadableHiddenField(default=serializers.CurrentUserDefault())
run_after_save = serializers.BooleanField(label=_("Execute after saving"), default=False, required=False) run_after_save = serializers.BooleanField(label=_("Run on save"), default=False, required=False)
nodes = serializers.ListField(required=False, child=serializers.CharField()) nodes = serializers.ListField(required=False, child=serializers.CharField())
date_last_run = serializers.DateTimeField(label=_('Date last run'), read_only=True) date_last_run = serializers.DateTimeField(label=_('Date last run'), read_only=True)
name = serializers.CharField(label=_('Name'), max_length=128, allow_blank=True, required=False) name = serializers.CharField(label=_('Name'), max_length=128, allow_blank=True, required=False)

View File

@ -1,12 +1,14 @@
from collections import defaultdict from collections import defaultdict
from django.utils import timezone
from accounts.const import AliasAccount from accounts.const import AliasAccount
from accounts.models import VirtualAccount from accounts.models import VirtualAccount
from assets.models import Asset, MyAsset from assets.models import Asset, MyAsset
from common.utils import lazyproperty from common.utils import lazyproperty
from orgs.utils import tmp_to_org, tmp_to_root_org from orgs.utils import tmp_to_org, tmp_to_root_org
from .permission import AssetPermissionUtil
from perms.const import ActionChoices from perms.const import ActionChoices
from .permission import AssetPermissionUtil
__all__ = ['PermAssetDetailUtil'] __all__ = ['PermAssetDetailUtil']
@ -40,6 +42,12 @@ class PermAssetDetailUtil:
def validate_permission(self, account_name, protocol): def validate_permission(self, account_name, protocol):
with tmp_to_org(self.asset.org): with tmp_to_org(self.asset.org):
if self.user.is_superuser:
account = self.asset.accounts.all().active().get(name=account_name)
account.actions = ActionChoices.all()
account.date_expired = timezone.now() + timezone.timedelta(days=365)
return account
protocols = self.get_permed_protocols_for_user(only_name=True) protocols = self.get_permed_protocols_for_user(only_name=True)
if 'all' not in protocols and protocol not in protocols: if 'all' not in protocols and protocol not in protocols:
return None return None