From ac4b6e5b969f1270a507d235b4011f8425346c5b Mon Sep 17 00:00:00 2001 From: feng626 <1304903146@qq.com> Date: Tue, 30 Nov 2021 16:04:08 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=B7=A5=E5=8D=95=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E8=B5=84=E4=BA=A7=E6=B7=BB=E5=8A=A0=E8=8A=82=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/assets/api/node.py | 3 +- apps/locale/zh/LC_MESSAGES/django.mo | 4 +- apps/locale/zh/LC_MESSAGES/django.po | 166 ++++++++++-------- apps/tickets/handler/apply_application.py | 1 + apps/tickets/handler/apply_asset.py | 18 +- .../meta/ticket_type/apply_application.py | 6 +- .../ticket/meta/ticket_type/apply_asset.py | 28 ++- 7 files changed, 138 insertions(+), 88 deletions(-) diff --git a/apps/assets/api/node.py b/apps/assets/api/node.py index a8164cd13..7e4ff61aa 100644 --- a/apps/assets/api/node.py +++ b/apps/assets/api/node.py @@ -13,6 +13,7 @@ from django.db.models.signals import m2m_changed from common.const.http import POST from common.exceptions import SomeoneIsDoingThis from common.const.signals import PRE_REMOVE, POST_REMOVE +from common.mixins.api import SuggestionMixin from assets.models import Asset from common.utils import get_logger, get_object_or_none from common.tree import TreeNodeSerializer @@ -41,7 +42,7 @@ __all__ = [ ] -class NodeViewSet(OrgModelViewSet): +class NodeViewSet(SuggestionMixin, OrgModelViewSet): model = Node filterset_fields = ('value', 'key', 'id') search_fields = ('value', ) diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index d718427e5..0798173e5 100644 --- a/apps/locale/zh/LC_MESSAGES/django.mo +++ b/apps/locale/zh/LC_MESSAGES/django.mo @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c9823f96465943a304034daf10ad6a98f2e02d8fe80a145f6e0196693a933387 -size 93547 +oid sha256:0fb4f116f97f4e3ec6e0f766936adba23ceb4367646cd8cc0d83e74cca06bc4e +size 93561 diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 7f902ed60..4d798968a 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: JumpServer 0.3.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-11-26 15:16+0800\n" +"POT-Creation-Date: 2021-11-30 16:35+0800\n" "PO-Revision-Date: 2021-05-20 10:54+0800\n" "Last-Translator: ibuler \n" "Language-Team: JumpServer team\n" @@ -167,7 +167,7 @@ msgstr "格式为逗号分隔的字符串, * 表示匹配所有. " #: users/templates/users/_select_user_modal.html:14 #: xpack/plugins/change_auth_plan/models/asset.py:35 #: xpack/plugins/change_auth_plan/models/asset.py:191 -#: xpack/plugins/cloud/serializers/account_attrs.py:62 +#: xpack/plugins/cloud/serializers/account_attrs.py:22 msgid "Username" msgstr "用户名" @@ -297,7 +297,7 @@ msgstr "应用管理" #: applications/serializers/application.py:88 assets/models/label.py:21 #: perms/models/application_permission.py:20 #: perms/serializers/application/user_permission.py:33 -#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:24 +#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:22 #: xpack/plugins/change_auth_plan/models/app.py:25 msgid "Category" msgstr "类别" @@ -308,7 +308,7 @@ msgstr "类别" #: perms/serializers/application/user_permission.py:34 #: terminal/models/storage.py:55 terminal/models/storage.py:116 #: tickets/models/flow.py:51 tickets/models/ticket.py:48 -#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:31 +#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:29 #: xpack/plugins/change_auth_plan/models/app.py:28 #: xpack/plugins/change_auth_plan/models/app.py:148 msgid "Type" @@ -331,7 +331,7 @@ msgstr "应用程序" #: applications/serializers/application.py:59 #: applications/serializers/application.py:89 assets/serializers/label.py:13 #: perms/serializers/application/permission.py:16 -#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:28 +#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:26 msgid "Category display" msgstr "类别名称" @@ -339,7 +339,7 @@ msgstr "类别名称" #: applications/serializers/application.py:91 #: assets/serializers/system_user.py:27 audits/serializers.py:29 #: perms/serializers/application/permission.py:17 -#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:35 +#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:33 #: tickets/serializers/ticket/ticket.py:22 #: tickets/serializers/ticket/ticket.py:168 msgid "Type display" @@ -357,7 +357,7 @@ msgstr "集群" #: applications/serializers/attrs/application_category/db.py:11 #: ops/models/adhoc.py:146 settings/serializers/auth/radius.py:14 -#: xpack/plugins/cloud/serializers/account_attrs.py:60 +#: xpack/plugins/cloud/serializers/account_attrs.py:68 msgid "Host" msgstr "主机" @@ -369,7 +369,7 @@ msgstr "主机" #: applications/serializers/attrs/application_type/sqlserver.py:11 #: assets/models/asset.py:215 assets/models/domain.py:62 #: settings/serializers/auth/radius.py:15 -#: xpack/plugins/cloud/serializers/account_attrs.py:61 +#: xpack/plugins/cloud/serializers/account_attrs.py:69 msgid "Port" msgstr "端口" @@ -386,7 +386,7 @@ msgstr "应用路径" #: xpack/plugins/change_auth_plan/serializers/asset.py:68 #: xpack/plugins/change_auth_plan/serializers/asset.py:71 #: xpack/plugins/change_auth_plan/serializers/asset.py:87 -#: xpack/plugins/cloud/serializers/account_attrs.py:44 +#: xpack/plugins/cloud/serializers/account_attrs.py:52 msgid "This field is required." msgstr "该字段是必填项。" @@ -409,7 +409,7 @@ msgstr "目标URL" #: xpack/plugins/change_auth_plan/models/base.py:39 #: xpack/plugins/change_auth_plan/models/base.py:114 #: xpack/plugins/change_auth_plan/models/base.py:182 -#: xpack/plugins/cloud/serializers/account_attrs.py:64 +#: xpack/plugins/cloud/serializers/account_attrs.py:24 msgid "Password" msgstr "密码" @@ -425,15 +425,15 @@ msgstr "目标URL" msgid "Number required" msgstr "需要为数字" -#: assets/api/node.py:65 +#: assets/api/node.py:66 msgid "You can't update the root node name" msgstr "不能修改根节点名称" -#: assets/api/node.py:72 +#: assets/api/node.py:73 msgid "You can't delete the root node ({})" msgstr "不能删除根节点 ({})" -#: assets/api/node.py:75 +#: assets/api/node.py:76 msgid "Deletion failed and the node contains assets" msgstr "删除失败,节点包含资产" @@ -584,7 +584,7 @@ msgid "Ok" msgstr "成功" #: assets/models/base.py:32 audits/models.py:102 -#: xpack/plugins/cloud/const.py:28 +#: xpack/plugins/cloud/const.py:29 msgid "Failed" msgstr "失败" @@ -1158,8 +1158,8 @@ msgstr "成功" #: audits/models.py:43 ops/models/command.py:30 perms/models/base.py:49 #: terminal/models/session.py:53 -#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:57 -#: tickets/serializers/ticket/meta/ticket_type/apply_asset.py:47 +#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:55 +#: tickets/serializers/ticket/meta/ticket_type/apply_asset.py:57 #: xpack/plugins/change_auth_plan/models/base.py:105 #: xpack/plugins/change_auth_plan/models/base.py:189 #: xpack/plugins/gathered_user/models.py:76 @@ -2647,8 +2647,8 @@ msgid "User group" msgstr "用户组" #: perms/models/base.py:50 -#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:60 -#: tickets/serializers/ticket/meta/ticket_type/apply_asset.py:50 +#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:58 +#: tickets/serializers/ticket/meta/ticket_type/apply_asset.py:60 #: users/models/user.py:585 msgid "Date expired" msgstr "失效日期" @@ -2943,7 +2943,7 @@ msgid "Client Id" msgstr "客户端 ID" #: settings/serializers/auth/oidc.py:18 -#: xpack/plugins/cloud/serializers/account_attrs.py:26 +#: xpack/plugins/cloud/serializers/account_attrs.py:34 msgid "Client Secret" msgstr "客户端密钥" @@ -4605,46 +4605,50 @@ msgstr "自定义用户" msgid "Ticket already closed" msgstr "工单已经关闭" -#: tickets/handler/apply_application.py:52 +#: tickets/handler/apply_application.py:53 msgid "Applied category" msgstr "申请的类别" -#: tickets/handler/apply_application.py:53 +#: tickets/handler/apply_application.py:54 msgid "Applied type" msgstr "申请的类型" -#: tickets/handler/apply_application.py:54 +#: tickets/handler/apply_application.py:55 msgid "Applied application group" msgstr "申请的应用组" -#: tickets/handler/apply_application.py:55 tickets/handler/apply_asset.py:48 +#: tickets/handler/apply_application.py:56 tickets/handler/apply_asset.py:52 msgid "Applied system user group" msgstr "申请的系统用户组" -#: tickets/handler/apply_application.py:56 tickets/handler/apply_asset.py:50 +#: tickets/handler/apply_application.py:57 tickets/handler/apply_asset.py:54 msgid "Applied date start" msgstr "申请的开始日期" -#: tickets/handler/apply_application.py:57 tickets/handler/apply_asset.py:51 +#: tickets/handler/apply_application.py:58 tickets/handler/apply_asset.py:55 msgid "Applied date expired" msgstr "申请的失效日期" -#: tickets/handler/apply_application.py:79 +#: tickets/handler/apply_application.py:80 msgid "" "Created by the ticket, ticket title: {}, ticket applicant: {}, ticket " "processor: {}, ticket ID: {}" msgstr "" "通过工单创建, 工单标题: {}, 工单申请人: {}, 工单处理人: {}, 工单 ID: {}" -#: tickets/handler/apply_asset.py:47 -msgid "Applied hostname group" -msgstr "申请的主机名组" +#: tickets/handler/apply_asset.py:50 +msgid "Applied node group" +msgstr "申请的节点名称组" -#: tickets/handler/apply_asset.py:49 +#: tickets/handler/apply_asset.py:51 +msgid "Applied hostname group" +msgstr "申请的主机名称组" + +#: tickets/handler/apply_asset.py:53 msgid "Applied actions" msgstr "申请的动作" -#: tickets/handler/apply_asset.py:72 +#: tickets/handler/apply_asset.py:77 msgid "" "Created by the ticket ticket title: {} ticket applicant: {} ticket " "processor: {} ticket ID: {}" @@ -4816,54 +4820,60 @@ msgstr "你的工单已被处理, 处理人 - {}" msgid "Ticket has processed - {} ({})" msgstr "你的工单已被处理, 处理人 - {} ({})" -#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:20 -#: tickets/serializers/ticket/meta/ticket_type/apply_asset.py:18 +#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:18 +#: tickets/serializers/ticket/meta/ticket_type/apply_asset.py:19 msgid "Apply name" msgstr "应用名称" -#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:39 +#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:37 msgid "Apply applications" msgstr "申请应用" -#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:44 +#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:42 msgid "Apply applications display" msgstr "应用名称名称" -#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:48 +#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:46 +#: tickets/serializers/ticket/meta/ticket_type/apply_asset.py:41 msgid "Apply system users" -msgstr "系统用户" +msgstr "申请的系统用户" -#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:53 +#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:51 msgid "Apply system user display" -msgstr "批准的系统用户名称" +msgstr "申请的系统用户名称" -#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:73 -#: tickets/serializers/ticket/meta/ticket_type/apply_asset.py:63 +#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:71 +#: tickets/serializers/ticket/meta/ticket_type/apply_asset.py:73 #: tickets/serializers/ticket/ticket.py:127 msgid "Permission named `{}` already exists" msgstr "授权名称 `{}` 已存在" -#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:90 -#: tickets/serializers/ticket/meta/ticket_type/apply_asset.py:71 +#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:88 +#: tickets/serializers/ticket/meta/ticket_type/apply_asset.py:87 msgid "The expiration date should be greater than the start date" msgstr "过期时间要大于开始时间" -#: tickets/serializers/ticket/meta/ticket_type/apply_asset.py:22 +#: tickets/serializers/ticket/meta/ticket_type/apply_asset.py:14 +msgid "Select at least one asset or node" +msgstr "资产或者节点至少选择一项" + +#: tickets/serializers/ticket/meta/ticket_type/apply_asset.py:23 +msgid "Apply nodes" +msgstr "申请节点" + +#: tickets/serializers/ticket/meta/ticket_type/apply_asset.py:27 +msgid "Apply nodes display" +msgstr "申请的节点名称" + +#: tickets/serializers/ticket/meta/ticket_type/apply_asset.py:32 msgid "Apply assets" msgstr "申请资产" -#: tickets/serializers/ticket/meta/ticket_type/apply_asset.py:26 -msgid "Approve assets display" -msgstr "批准的资产名称" - -#: tickets/serializers/ticket/meta/ticket_type/apply_asset.py:31 -msgid "Approve system users" -msgstr "批准的系统用户" - -#: tickets/serializers/ticket/meta/ticket_type/apply_asset.py:35 -#: tickets/serializers/ticket/meta/ticket_type/apply_asset.py:43 +#: tickets/serializers/ticket/meta/ticket_type/apply_asset.py:36 +#: tickets/serializers/ticket/meta/ticket_type/apply_asset.py:45 +#: tickets/serializers/ticket/meta/ticket_type/apply_asset.py:53 msgid "Apply assets display" -msgstr "批准的资产名称" +msgstr "申请的资产名称" #: tickets/serializers/ticket/meta/ticket_type/command_confirm.py:12 msgid "Run user" @@ -5740,34 +5750,40 @@ msgid "Qingyun Private Cloud" msgstr "青云私有云" #: xpack/plugins/cloud/const.py:19 +#, fuzzy +#| msgid "Tencent Cloud" +msgid "OpenStack Cloud" +msgstr "腾讯云" + +#: xpack/plugins/cloud/const.py:20 msgid "Google Cloud Platform" msgstr "谷歌云" -#: xpack/plugins/cloud/const.py:23 +#: xpack/plugins/cloud/const.py:24 msgid "Instance name" msgstr "实例名称" -#: xpack/plugins/cloud/const.py:24 +#: xpack/plugins/cloud/const.py:25 msgid "Instance name and Partial IP" msgstr "实例名称和部分IP" -#: xpack/plugins/cloud/const.py:29 +#: xpack/plugins/cloud/const.py:30 msgid "Succeed" msgstr "成功" -#: xpack/plugins/cloud/const.py:33 +#: xpack/plugins/cloud/const.py:34 msgid "Unsync" msgstr "未同步" -#: xpack/plugins/cloud/const.py:34 +#: xpack/plugins/cloud/const.py:35 msgid "New Sync" msgstr "新同步" -#: xpack/plugins/cloud/const.py:35 +#: xpack/plugins/cloud/const.py:36 msgid "Synced" msgstr "已同步" -#: xpack/plugins/cloud/const.py:36 +#: xpack/plugins/cloud/const.py:37 msgid "Released" msgstr "已释放" @@ -5999,28 +6015,40 @@ msgstr "" msgid "AccessKey Secret" msgstr "" -#: xpack/plugins/cloud/serializers/account_attrs.py:23 +#: xpack/plugins/cloud/serializers/account_attrs.py:31 msgid "Client ID" msgstr "客户端 ID" -#: xpack/plugins/cloud/serializers/account_attrs.py:29 +#: xpack/plugins/cloud/serializers/account_attrs.py:37 msgid "Tenant ID" msgstr "租户 ID" -#: xpack/plugins/cloud/serializers/account_attrs.py:32 +#: xpack/plugins/cloud/serializers/account_attrs.py:40 msgid "Subscription ID" msgstr "订阅 ID" -#: xpack/plugins/cloud/serializers/account_attrs.py:87 -#: xpack/plugins/cloud/serializers/account_attrs.py:92 +#: xpack/plugins/cloud/serializers/account_attrs.py:91 +#: xpack/plugins/cloud/serializers/account_attrs.py:96 msgid "API Endpoint" msgstr "API 端点" -#: xpack/plugins/cloud/serializers/account_attrs.py:98 +#: xpack/plugins/cloud/serializers/account_attrs.py:101 +#, fuzzy +#| msgid "Target url" +msgid "auth url" +msgstr "目标URL" + +#: xpack/plugins/cloud/serializers/account_attrs.py:103 +#, fuzzy +#| msgid "Domain name" +msgid "user domain name" +msgstr "网域名称" + +#: xpack/plugins/cloud/serializers/account_attrs.py:110 msgid "Service account key" msgstr "账户密钥" -#: xpack/plugins/cloud/serializers/account_attrs.py:99 +#: xpack/plugins/cloud/serializers/account_attrs.py:111 msgid "The file is in JSON format" msgstr "JSON 格式的文件" diff --git a/apps/tickets/handler/apply_application.py b/apps/tickets/handler/apply_application.py index 5cfc06e38..5e20e89f9 100644 --- a/apps/tickets/handler/apply_application.py +++ b/apps/tickets/handler/apply_application.py @@ -1,4 +1,5 @@ from django.utils.translation import ugettext as _ + from orgs.utils import tmp_to_org, tmp_to_root_org from applications.const import AppCategory, AppType from applications.models import Application diff --git a/apps/tickets/handler/apply_asset.py b/apps/tickets/handler/apply_asset.py index f457efdba..a13f6e008 100644 --- a/apps/tickets/handler/apply_asset.py +++ b/apps/tickets/handler/apply_asset.py @@ -1,11 +1,9 @@ -from assets.models import Asset -from assets.models import SystemUser - -from .base import BaseHandler from django.utils.translation import ugettext as _ +from assets.models import Node, Asset, SystemUser from perms.models import AssetPermission, Action from orgs.utils import tmp_to_org, tmp_to_root_org +from .base import BaseHandler class Handler(BaseHandler): @@ -22,17 +20,22 @@ class Handler(BaseHandler): apply_actions_display = Action.value_to_choices_display(apply_actions) meta_display_values = [apply_actions_display] meta_display = dict(zip(meta_display_fields, meta_display_values)) - apply_assets = self.ticket.meta.get('apply_assets') + apply_nodes = self.ticket.meta.get('apply_nodes', []) + apply_assets = self.ticket.meta.get('apply_assets', []) apply_system_users = self.ticket.meta.get('apply_system_users') with tmp_to_org(self.ticket.org_id): meta_display.update({ + 'apply_nodes_display': [str(i) for i in Node.objects.filter(id__in=apply_nodes)], 'apply_assets_display': [str(i) for i in Asset.objects.filter(id__in=apply_assets)], - 'apply_system_users_display': [str(i)for i in SystemUser.objects.filter(id__in=apply_system_users)] + 'apply_system_users_display': [ + str(i) for i in SystemUser.objects.filter(id__in=apply_system_users) + ] }) return meta_display # body def _construct_meta_body_of_open(self): + apply_nodes = self.ticket.meta.get('apply_nodes_display', []) apply_assets = self.ticket.meta.get('apply_assets_display', []) apply_system_users = self.ticket.meta.get('apply_system_users_display', []) apply_actions_display = self.ticket.meta.get('apply_actions_display', []) @@ -44,6 +47,7 @@ class Handler(BaseHandler): {}: {}, {}: {} '''.format( + _("Applied node group"), ','.join(apply_nodes), _("Applied hostname group"), ','.join(apply_assets), _("Applied system user group"), ','.join(apply_system_users), _("Applied actions"), ','.join(apply_actions_display), @@ -60,6 +64,7 @@ class Handler(BaseHandler): return asset_permission apply_permission_name = self.ticket.meta.get('apply_permission_name', ) + apply_nodes = self.ticket.meta.get('apply_nodes', []) apply_assets = self.ticket.meta.get('apply_assets', []) apply_system_users = self.ticket.meta.get('apply_system_users', []) apply_actions = self.ticket.meta.get('apply_actions', Action.NONE) @@ -94,6 +99,7 @@ class Handler(BaseHandler): with tmp_to_org(self.ticket.org_id): asset_permission = AssetPermission.objects.create(**permission_data) asset_permission.users.add(self.ticket.applicant) + asset_permission.nodes.set(apply_nodes) asset_permission.assets.set(apply_assets) asset_permission.system_users.set(apply_system_users) diff --git a/apps/tickets/serializers/ticket/meta/ticket_type/apply_application.py b/apps/tickets/serializers/ticket/meta/ticket_type/apply_application.py index 98e303b1c..a7f60ae82 100644 --- a/apps/tickets/serializers/ticket/meta/ticket_type/apply_application.py +++ b/apps/tickets/serializers/ticket/meta/ticket_type/apply_application.py @@ -1,13 +1,11 @@ -from datetime import datetime - -from rest_framework import serializers from django.utils.translation import ugettext_lazy as _ +from rest_framework import serializers + from perms.models import ApplicationPermission from applications.const import AppCategory, AppType from orgs.utils import tmp_to_org from tickets.models import Ticket from applications.models import Application -from assets.models import SystemUser from .common import DefaultPermissionName __all__ = [ diff --git a/apps/tickets/serializers/ticket/meta/ticket_type/apply_asset.py b/apps/tickets/serializers/ticket/meta/ticket_type/apply_asset.py index 19da551ec..b03fe9231 100644 --- a/apps/tickets/serializers/ticket/meta/ticket_type/apply_asset.py +++ b/apps/tickets/serializers/ticket/meta/ticket_type/apply_asset.py @@ -1,7 +1,6 @@ -from datetime import datetime - from django.utils.translation import ugettext_lazy as _ from rest_framework import serializers + from perms.serializers import ActionsField from perms.models import AssetPermission from orgs.utils import tmp_to_org @@ -12,23 +11,34 @@ __all__ = [ 'ApplySerializer', ] +asset_or_node_help_text = _("Select at least one asset or node") + class ApplySerializer(serializers.Serializer): apply_permission_name = serializers.CharField( max_length=128, default=DefaultPermissionName(), label=_('Apply name') ) + apply_nodes = serializers.ListField( + required=False, allow_null=True, child=serializers.UUIDField(), + label=_('Apply nodes'), help_text=asset_or_node_help_text, + default=list + ) + apply_nodes_display = serializers.ListField( + child=serializers.CharField(), label=_('Apply nodes display'), required=False + ) # 申请信息 apply_assets = serializers.ListField( - required=True, allow_null=True, child=serializers.UUIDField(), label=_('Apply assets') + required=False, allow_null=True, child=serializers.UUIDField(), + label=_('Apply assets'), help_text=asset_or_node_help_text ) apply_assets_display = serializers.ListField( required=False, read_only=True, child=serializers.CharField(), - label=_('Approve assets display'), allow_null=True, - default=list, + label=_('Apply assets display'), allow_null=True, + default=list ) apply_system_users = serializers.ListField( required=True, allow_null=True, child=serializers.UUIDField(), - label=_('Approve system users') + label=_('Apply system users') ) apply_system_users_display = serializers.ListField( required=False, read_only=True, child=serializers.CharField(), @@ -64,6 +74,12 @@ class ApplySerializer(serializers.Serializer): )) def validate(self, attrs): + if not attrs.get('apply_nodes') and not attrs.get('apply_assets'): + raise serializers.ValidationError({ + 'apply_nodes': asset_or_node_help_text, + 'apply_assets': asset_or_node_help_text, + }) + apply_date_start = attrs['apply_date_start'].strftime('%Y-%m-%d %H:%M:%S') apply_date_expired = attrs['apply_date_expired'].strftime('%Y-%m-%d %H:%M:%S')