mirror of https://github.com/jumpserver/jumpserver
fix: Solve audit job and variable bugs
parent
1ee57cfda0
commit
fcdc2b9510
|
@ -66,7 +66,7 @@ class JobsAuditViewSet(OrgModelViewSet):
|
|||
search_fields = ['creator__name']
|
||||
filterset_fields = ['creator__name']
|
||||
serializer_class = JobsAuditSerializer
|
||||
ordering = ['-is_periodic', '-date_created']
|
||||
ordering = ['-is_periodic', '-date_updated']
|
||||
http_method_names = ['get', 'options', 'patch']
|
||||
|
||||
def get_queryset(self):
|
||||
|
|
|
@ -35,8 +35,14 @@ class JobLogSerializer(JobExecutionSerializer):
|
|||
|
||||
|
||||
class JobsAuditSerializer(JobSerializer):
|
||||
material = serializers.ReadOnlyField(label=_("Command"))
|
||||
summary = serializers.ReadOnlyField(label=_("Summary"))
|
||||
|
||||
class Meta(JobSerializer.Meta):
|
||||
fields = JobSerializer.Meta.fields
|
||||
read_only_fields = [
|
||||
"id", 'name', 'args', 'material', 'type', 'crontab', 'interval', 'date_last_run', 'summary', 'created_by'
|
||||
]
|
||||
fields = read_only_fields + ['is_periodic']
|
||||
|
||||
def validate(self, attrs):
|
||||
allowed_fields = {'is_periodic'}
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: JumpServer 0.3.3\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-11-11 19:17+0800\n"
|
||||
"POT-Creation-Date: 2024-11-13 11:11+0800\n"
|
||||
"PO-Revision-Date: 2021-05-20 10:54+0800\n"
|
||||
"Last-Translator: ibuler <ibuler@qq.com>\n"
|
||||
"Language-Team: JumpServer team<ibuler@qq.com>\n"
|
||||
|
@ -593,7 +593,7 @@ msgstr "结束日期"
|
|||
#: accounts/models/automations/change_secret.py:44
|
||||
#: assets/models/automations/base.py:113
|
||||
#: assets/serializers/automations/base.py:39 audits/models.py:208
|
||||
#: audits/serializers.py:54 ops/models/base.py:49 ops/models/job.py:239
|
||||
#: audits/serializers.py:69 ops/models/base.py:49 ops/models/job.py:239
|
||||
#: terminal/models/applet/applet.py:331 terminal/models/applet/host.py:140
|
||||
#: terminal/models/component/status.py:30
|
||||
#: terminal/models/virtualapp/virtualapp.py:99
|
||||
|
@ -665,7 +665,7 @@ msgstr "触发方式"
|
|||
|
||||
#: accounts/models/automations/push_account.py:16 acls/models/base.py:41
|
||||
#: acls/serializers/base.py:57 assets/models/cmd_filter.py:81
|
||||
#: audits/models.py:92 audits/serializers.py:84
|
||||
#: audits/models.py:92 audits/serializers.py:99
|
||||
#: authentication/serializers/connect_token_secret.py:119
|
||||
#: authentication/templates/authentication/_access_key_modal.html:34
|
||||
#: perms/serializers/permission.py:52 perms/serializers/permission.py:74
|
||||
|
@ -884,8 +884,8 @@ msgstr "类别"
|
|||
#: acls/serializers/command_acl.py:19 assets/models/automations/base.py:20
|
||||
#: assets/models/cmd_filter.py:74 assets/models/platform.py:96
|
||||
#: assets/serializers/asset/common.py:146 assets/serializers/platform.py:159
|
||||
#: assets/serializers/platform.py:171 audits/serializers.py:53
|
||||
#: audits/serializers.py:170
|
||||
#: assets/serializers/platform.py:171 audits/serializers.py:68
|
||||
#: audits/serializers.py:185
|
||||
#: authentication/serializers/connect_token_secret.py:126 ops/models/job.py:153
|
||||
#: perms/serializers/user_permission.py:27 terminal/models/applet/applet.py:40
|
||||
#: terminal/models/component/storage.py:58
|
||||
|
@ -958,7 +958,7 @@ msgstr "ID"
|
|||
#: acls/templates/acls/user_login_reminder.html:8
|
||||
#: assets/models/cmd_filter.py:24 assets/models/label.py:16 audits/models.py:54
|
||||
#: audits/models.py:90 audits/models.py:172 audits/models.py:271
|
||||
#: audits/serializers.py:171 authentication/models/connection_token.py:32
|
||||
#: audits/serializers.py:186 authentication/models/connection_token.py:32
|
||||
#: authentication/models/ssh_key.py:22 authentication/models/sso_token.py:16
|
||||
#: notifications/models/notification.py:12
|
||||
#: perms/api/user_permission/mixin.py:55 perms/models/asset_permission.py:63
|
||||
|
@ -1587,7 +1587,7 @@ msgid "Login city"
|
|||
msgstr "登录城市"
|
||||
|
||||
#: acls/templates/acls/user_login_reminder.html:11 audits/models.py:197
|
||||
#: audits/models.py:266 audits/serializers.py:68
|
||||
#: audits/models.py:266 audits/serializers.py:83
|
||||
msgid "User agent"
|
||||
msgstr "用户代理"
|
||||
|
||||
|
@ -2821,7 +2821,7 @@ msgid "Finished"
|
|||
msgstr "结束"
|
||||
|
||||
#: audits/const.py:46 settings/serializers/terminal.py:6
|
||||
#: terminal/models/applet/host.py:26 terminal/models/component/terminal.py:174
|
||||
#: terminal/models/applet/host.py:26 terminal/models/component/terminal.py:182
|
||||
#: terminal/models/virtualapp/provider.py:14 terminal/serializers/session.py:57
|
||||
#: terminal/serializers/session.py:113
|
||||
msgid "Terminal"
|
||||
|
@ -2866,7 +2866,7 @@ msgstr "作业审计日志"
|
|||
msgid "Remote addr"
|
||||
msgstr "远端地址"
|
||||
|
||||
#: audits/models.py:61 audits/serializers.py:38
|
||||
#: audits/models.py:61 audits/serializers.py:53
|
||||
msgid "Operate"
|
||||
msgstr "操作"
|
||||
|
||||
|
@ -2891,12 +2891,12 @@ msgstr "会话"
|
|||
msgid "File transfer log"
|
||||
msgstr "文件传输"
|
||||
|
||||
#: audits/models.py:94 audits/serializers.py:86
|
||||
#: audits/models.py:94 audits/serializers.py:101
|
||||
msgid "Resource Type"
|
||||
msgstr "资源类型"
|
||||
|
||||
#: audits/models.py:95 audits/models.py:98 audits/models.py:144
|
||||
#: audits/serializers.py:85 labels/serializers.py:46
|
||||
#: audits/serializers.py:100 labels/serializers.py:46
|
||||
msgid "Resource"
|
||||
msgstr "资源"
|
||||
|
||||
|
@ -2938,7 +2938,7 @@ msgstr "登录方式"
|
|||
msgid "Login IP"
|
||||
msgstr "登录 IP"
|
||||
|
||||
#: audits/models.py:200 audits/serializers.py:52
|
||||
#: audits/models.py:200 audits/serializers.py:67
|
||||
#: authentication/templates/authentication/_mfa_confirm_modal.html:14
|
||||
#: users/forms/profile.py:63 users/models/user/__init__.py:79
|
||||
#: users/serializers/profile.py:70
|
||||
|
@ -2982,20 +2982,20 @@ msgstr "下线用户会话"
|
|||
msgid "Creator"
|
||||
msgstr "创建者"
|
||||
|
||||
#: audits/serializers.py:69
|
||||
#: audits/serializers.py:84
|
||||
msgid "Reason display"
|
||||
msgstr "原因描述"
|
||||
|
||||
#: audits/serializers.py:70 audits/serializers.py:184
|
||||
#: audits/serializers.py:85 audits/serializers.py:199
|
||||
msgid "Auth backend display"
|
||||
msgstr "认证方式"
|
||||
|
||||
#: audits/serializers.py:134
|
||||
#: audits/serializers.py:149
|
||||
#, python-format
|
||||
msgid "%s %s this resource"
|
||||
msgstr "用户 %s %s 了当前资源"
|
||||
|
||||
#: audits/serializers.py:172 authentication/models/connection_token.py:47
|
||||
#: audits/serializers.py:187 authentication/models/connection_token.py:47
|
||||
#: authentication/models/temp_token.py:13 perms/models/asset_permission.py:80
|
||||
#: tickets/models/ticket/apply_application.py:31
|
||||
#: tickets/models/ticket/apply_asset.py:20 users/models/user/__init__.py:98
|
||||
|
@ -4719,7 +4719,7 @@ msgid ""
|
|||
"File size exceeds maximum limit. Please select a file smaller than {limit}MB"
|
||||
msgstr "文件大小超过最大限制。请选择小于 {limit}MB 的文件。"
|
||||
|
||||
#: ops/api/job.py:231
|
||||
#: ops/api/job.py:235
|
||||
msgid ""
|
||||
"The task is being created and cannot be interrupted. Please try again later."
|
||||
msgstr "正在创建任务,无法中断,请稍后重试。"
|
||||
|
@ -4971,7 +4971,7 @@ msgstr "其它参数"
|
|||
msgid "Date published"
|
||||
msgstr "发布日期"
|
||||
|
||||
#: ops/models/celery.py:113
|
||||
#: ops/models/celery.py:124
|
||||
msgid "Celery Task Execution"
|
||||
msgstr "Celery 任务执行"
|
||||
|
||||
|
@ -4992,10 +4992,8 @@ msgid "Parameters define"
|
|||
msgstr "参数定义"
|
||||
|
||||
#: ops/models/job.py:159
|
||||
#, fuzzy
|
||||
#| msgid "Periodic run"
|
||||
msgid "Periodic variable"
|
||||
msgstr "周期执行"
|
||||
msgstr "周期执行变量"
|
||||
|
||||
#: ops/models/job.py:160
|
||||
msgid "Run as"
|
||||
|
@ -5031,40 +5029,32 @@ msgid "VCS URL"
|
|||
msgstr "VCS URL"
|
||||
|
||||
#: ops/models/variable.py:11
|
||||
#, fuzzy
|
||||
#| msgid "Variable Type"
|
||||
msgid "Variable name"
|
||||
msgstr "参数类型"
|
||||
msgstr "变量名"
|
||||
|
||||
#: ops/models/variable.py:12
|
||||
msgid ""
|
||||
"The variable name used in the script has a fixed prefix 'jms_' followed by "
|
||||
"the input variable name. For example, if the variable name is 'name,' the "
|
||||
"final generated environment variable will be 'jms_name'."
|
||||
msgstr ""
|
||||
msgstr "在脚本使用的变量名称,固定前缀 jms_ + 输入的变量名,例如变量名name,则最终生成环境变量为 jms_name"
|
||||
|
||||
#: ops/models/variable.py:16
|
||||
#, fuzzy
|
||||
#| msgid "Default"
|
||||
msgid "Default Value"
|
||||
msgstr "默认"
|
||||
|
||||
#: ops/models/variable.py:18
|
||||
#, fuzzy
|
||||
#| msgid "Variable Type"
|
||||
msgid "Variable type"
|
||||
msgstr "参数类型"
|
||||
msgstr "变量类型"
|
||||
|
||||
#: ops/models/variable.py:21 ops/serializers/variable.py:23
|
||||
#: ops/models/variable.py:21 ops/serializers/variable.py:25
|
||||
msgid "ExtraVars"
|
||||
msgstr ""
|
||||
msgstr "额外参数"
|
||||
|
||||
#: ops/models/variable.py:49 ops/serializers/adhoc.py:16
|
||||
#: ops/serializers/job.py:22 ops/serializers/playbook.py:21
|
||||
#, fuzzy
|
||||
#| msgid "Variable Type"
|
||||
msgid "Variable"
|
||||
msgstr "参数类型"
|
||||
msgstr "变量"
|
||||
|
||||
#: ops/notifications.py:20
|
||||
msgid "Server performance"
|
||||
|
@ -5126,11 +5116,11 @@ msgstr "任务 ID"
|
|||
msgid "You do not have permission for the current job."
|
||||
msgstr "你没有当前作业的权限。"
|
||||
|
||||
#: ops/serializers/variable.py:20
|
||||
#: ops/serializers/variable.py:22
|
||||
msgid "Variable Type"
|
||||
msgstr "参数类型"
|
||||
msgstr "变量类型"
|
||||
|
||||
#: ops/serializers/variable.py:25
|
||||
#: ops/serializers/variable.py:27
|
||||
msgid ""
|
||||
"Each item is on a separate line, with each line separated by a colon. The "
|
||||
"part before the colon is the display content, and the part after the colon "
|
||||
|
@ -6586,8 +6576,6 @@ msgid "Vault"
|
|||
msgstr "启用 Vault"
|
||||
|
||||
#: settings/serializers/feature.py:53
|
||||
#, fuzzy
|
||||
#| msgid "Provider"
|
||||
msgid "Vault provider"
|
||||
msgstr "云服务商"
|
||||
|
||||
|
@ -6611,8 +6599,6 @@ msgstr "挂载点"
|
|||
|
||||
#: settings/serializers/feature.py:94
|
||||
#: xpack/plugins/cloud/serializers/account_attrs.py:41
|
||||
#, fuzzy
|
||||
#| msgid "Client ID"
|
||||
msgid "Tenant ID"
|
||||
msgstr "客户端 ID"
|
||||
|
||||
|
@ -7899,7 +7885,7 @@ msgstr "远端地址"
|
|||
msgid "Application User"
|
||||
msgstr "应用用户"
|
||||
|
||||
#: terminal/models/component/terminal.py:176
|
||||
#: terminal/models/component/terminal.py:184
|
||||
msgid "Can view terminal config"
|
||||
msgstr "可以查看终端配置"
|
||||
|
||||
|
@ -8823,7 +8809,7 @@ msgstr "工单快照"
|
|||
msgid "Please try again"
|
||||
msgstr "请再次尝试"
|
||||
|
||||
#: tickets/models/ticket/general.py:481
|
||||
#: tickets/models/ticket/general.py:483
|
||||
msgid "Super ticket"
|
||||
msgstr "超级工单"
|
||||
|
||||
|
|
|
@ -1413,5 +1413,6 @@
|
|||
"setVariable": "Set variable",
|
||||
"JobsAudit": "Jobs audit",
|
||||
"JobList": "Job List",
|
||||
"StopJobMsg": "Stop job successfully"
|
||||
"StopJobMsg": "Stop job successfully",
|
||||
"ExtraArgsFormatError": "Format error, please enter according to the requirements"
|
||||
}
|
|
@ -1418,5 +1418,6 @@
|
|||
"setVariable": "设置参数",
|
||||
"JobsAudit": "作业审计",
|
||||
"JobList": "作业列表",
|
||||
"StopJobMsg": "停止成功"
|
||||
"StopJobMsg": "停止成功",
|
||||
"ExtraArgsFormatError": "格式错误,请按要求输入"
|
||||
}
|
|
@ -1,7 +1,9 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from rest_framework import serializers
|
||||
from rest_framework.exceptions import ValidationError
|
||||
|
||||
from common.serializers.fields import ReadableHiddenField, LabeledChoiceField, EncryptedField
|
||||
from common.serializers.mixin import CommonBulkModelSerializer
|
||||
|
@ -15,6 +17,13 @@ __all__ = [
|
|||
|
||||
|
||||
class VariableSerializer(CommonBulkModelSerializer):
|
||||
name = serializers.CharField(max_length=1024, label=_('Name'), required=True)
|
||||
var_name = serializers.CharField(
|
||||
max_length=1024, required=True, label=_('Variable name'),
|
||||
help_text=_("The variable name used in the script has a fixed prefix 'jms_' followed by the input variable "
|
||||
"name. For example, if the variable name is 'name,' the final generated environment variable will "
|
||||
"be 'jms_name'.")
|
||||
)
|
||||
creator = ReadableHiddenField(default=serializers.CurrentUserDefault())
|
||||
type = LabeledChoiceField(
|
||||
choices=FieldType.choices, default=FieldType.text, label=_("Variable Type")
|
||||
|
@ -82,64 +91,68 @@ class PlaybookVariableSerializer(VariableSerializer):
|
|||
fields = VariableSerializer.Meta.fields
|
||||
|
||||
|
||||
def create_dynamic_text_choices(options):
|
||||
"""
|
||||
动态创建一个 TextChoices 子类。`options` 应该是一个列表,
|
||||
格式为 [(value1, display1), (value2, display2), ...]
|
||||
"""
|
||||
attrs = {
|
||||
key.upper(): value for value, key in options
|
||||
}
|
||||
attrs['choices'] = options
|
||||
return type('DynamicTextChoices', (models.TextChoices,), attrs)
|
||||
|
||||
|
||||
class VariableFormDataSerializer(serializers.Serializer):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
request = self.context.get('request')
|
||||
if not request:
|
||||
return
|
||||
|
||||
params = request.query_params
|
||||
if params.get('format') == 'openapi':
|
||||
return
|
||||
|
||||
job = params.get('job')
|
||||
adhoc = params.get('adhoc')
|
||||
playbook = params.get('playbook')
|
||||
if job:
|
||||
variables = Variable.objects.filter(job=job).all()
|
||||
elif adhoc:
|
||||
variables = Variable.objects.filter(adhoc=adhoc).all()
|
||||
else:
|
||||
variables = Variable.objects.filter(playbook=playbook).all()
|
||||
|
||||
if not any([job, adhoc, playbook]):
|
||||
raise ValidationError("One of 'job', 'adhoc', or 'playbook' is required.")
|
||||
|
||||
try:
|
||||
variables = Variable.objects.filter(
|
||||
job=job if job else None,
|
||||
adhoc=adhoc if adhoc else None,
|
||||
playbook=playbook if playbook else None
|
||||
).all()
|
||||
except ObjectDoesNotExist:
|
||||
raise ValidationError("Invalid job, adhoc, or playbook ID.")
|
||||
|
||||
dynamic_fields = [var.form_data for var in variables]
|
||||
|
||||
if dynamic_fields:
|
||||
for field in dynamic_fields:
|
||||
field_type = field['type']
|
||||
required = field['required']
|
||||
var_name = field["var_name"]
|
||||
label = field["label"]
|
||||
help_text = field['help_text']
|
||||
default = field['default']
|
||||
if field_type == FieldType.text:
|
||||
self.fields[var_name] = serializers.CharField(
|
||||
max_length=1024, label=label, help_text=help_text, required=required
|
||||
)
|
||||
elif field_type == FieldType.select:
|
||||
extra_args = field.get('extra_args', {})
|
||||
options = extra_args.get('options', '').splitlines()
|
||||
for field in dynamic_fields:
|
||||
self._add_field(field)
|
||||
|
||||
DynamicFieldType = models.TextChoices(
|
||||
'DynamicFieldType',
|
||||
{
|
||||
option.split(':')[0]: option.split(':')[1] for option in
|
||||
options
|
||||
}
|
||||
)
|
||||
self.fields[var_name] = LabeledChoiceField(
|
||||
choices=DynamicFieldType.choices, required=required, label=label,
|
||||
help_text=help_text
|
||||
)
|
||||
if required and default is not None:
|
||||
self.fields[var_name].default = default
|
||||
def _add_field(self, field):
|
||||
field_type = field['type']
|
||||
required = field['required']
|
||||
var_name = field["var_name"]
|
||||
label = field["label"]
|
||||
help_text = field['help_text']
|
||||
default = field.get('default', None)
|
||||
|
||||
if field_type == FieldType.text:
|
||||
self.fields[var_name] = serializers.CharField(
|
||||
max_length=1024, label=label, help_text=help_text, required=required
|
||||
)
|
||||
elif field_type == FieldType.select:
|
||||
self._add_select_field(field, var_name, required, label, help_text)
|
||||
|
||||
if required and default is not None:
|
||||
self.fields[var_name].default = default
|
||||
|
||||
def _add_select_field(self, field, var_name, required, label, help_text):
|
||||
extra_args = field.get('extra_args', {})
|
||||
options = extra_args.get('options', '').splitlines()
|
||||
|
||||
try:
|
||||
options_data = {option.split(':')[0]: option.split(':')[1] for option in options}
|
||||
except Exception as e:
|
||||
raise ValidationError(f"Invalid options format: {str(e)}")
|
||||
|
||||
DynamicFieldType = models.TextChoices('DynamicFieldType', options_data)
|
||||
self.fields[var_name] = LabeledChoiceField(
|
||||
choices=DynamicFieldType.choices, required=required, label=label,
|
||||
help_text=help_text
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue