diff --git a/apps/audits/api.py b/apps/audits/api.py index f0504ad7a..253b347a4 100644 --- a/apps/audits/api.py +++ b/apps/audits/api.py @@ -22,6 +22,9 @@ from common.plugins.es import QuerySet as ESQuerySet from common.sessions.cache import user_session_manager from common.storage.ftp_file import FTPFileStorageHandler from common.utils import is_uuid, get_logger, lazyproperty +from ops.const import Types +from ops.models import Job +from ops.serializers.job import JobSerializer from orgs.mixins.api import OrgReadonlyModelViewSet, OrgModelViewSet from orgs.models import Organization from orgs.utils import current_org, tmp_to_root_org @@ -39,14 +42,14 @@ from .serializers import ( FTPLogSerializer, UserLoginLogSerializer, JobLogSerializer, OperateLogSerializer, OperateLogActionDetailSerializer, PasswordChangeLogSerializer, ActivityUnionLogSerializer, - FileSerializer, UserSessionSerializer + FileSerializer, UserSessionSerializer, JobsAuditSerializer ) from .utils import construct_userlogin_usernames logger = get_logger(__name__) -class JobAuditViewSet(OrgReadonlyModelViewSet): +class JobLogAuditViewSet(OrgReadonlyModelViewSet): model = JobLog extra_filter_backends = [DatetimeRangeFilterBackend] date_range_filter_fields = [ @@ -58,6 +61,20 @@ class JobAuditViewSet(OrgReadonlyModelViewSet): ordering = ['-date_start'] +class JobsAuditViewSet(OrgModelViewSet): + model = Job + search_fields = ['creator__name'] + filterset_fields = ['creator__name'] + serializer_class = JobsAuditSerializer + ordering = ['-is_periodic', '-date_created'] + http_method_names = ['get', 'options', 'patch'] + + def get_queryset(self): + queryset = super().get_queryset() + queryset = queryset.exclude(type=Types.upload_file).filter(instant=False) + return queryset + + class FTPLogViewSet(OrgModelViewSet): model = FTPLog serializer_class = FTPLogSerializer diff --git a/apps/audits/serializers.py b/apps/audits/serializers.py index d2a019e4c..56824343f 100644 --- a/apps/audits/serializers.py +++ b/apps/audits/serializers.py @@ -7,7 +7,7 @@ from audits.backends.db import OperateLogStore from common.serializers.fields import LabeledChoiceField, ObjectRelatedField from common.utils import reverse, i18n_trans from common.utils.timezone import as_current_tz -from ops.serializers.job import JobExecutionSerializer +from ops.serializers.job import JobExecutionSerializer, JobSerializer from orgs.mixins.serializers import BulkOrgResourceModelSerializer from terminal.models import Session from users.models import User @@ -34,6 +34,21 @@ class JobLogSerializer(JobExecutionSerializer): } +class JobsAuditSerializer(JobSerializer): + class Meta(JobSerializer.Meta): + fields = JobSerializer.Meta.fields + + def validate(self, attrs): + allowed_fields = {'is_periodic'} + submitted_fields = set(attrs.keys()) + invalid_fields = submitted_fields - allowed_fields + if invalid_fields: + raise serializers.ValidationError( + f"Updating {', '.join(invalid_fields)} fields is not allowed" + ) + return attrs + + class FTPLogSerializer(serializers.ModelSerializer): operate = LabeledChoiceField(choices=OperateChoices.choices, label=_("Operate")) diff --git a/apps/audits/urls/api_urls.py b/apps/audits/urls/api_urls.py index 765470afb..0af151070 100644 --- a/apps/audits/urls/api_urls.py +++ b/apps/audits/urls/api_urls.py @@ -13,7 +13,9 @@ router.register(r'ftp-logs', api.FTPLogViewSet, 'ftp-log') router.register(r'login-logs', api.UserLoginLogViewSet, 'login-log') router.register(r'operate-logs', api.OperateLogViewSet, 'operate-log') router.register(r'password-change-logs', api.PasswordChangeLogViewSet, 'password-change-log') -router.register(r'job-logs', api.JobAuditViewSet, 'job-log') +router.register(r'job-logs', api.JobLogAuditViewSet, 'job-log') +router.register(r'jobs', api.JobsAuditViewSet, 'jobs') + router.register(r'my-login-logs', api.MyLoginLogViewSet, 'my-login-log') router.register(r'user-sessions', api.UserSessionViewSet, 'user-session') diff --git a/apps/i18n/lina/en.json b/apps/i18n/lina/en.json index 88b4658e9..85e547890 100644 --- a/apps/i18n/lina/en.json +++ b/apps/i18n/lina/en.json @@ -200,7 +200,7 @@ "BaseCommandFilterAclList": "Command filter", "BaseConnectMethodACL": "Connect Method ACL", "BaseFlowSetUp": "Flow Set Up", - "BaseJobManagement": "Job Management", + "BaseJobManagement": "Job List", "BaseLoginLog": "Login Log", "BaseMyAssets": "My Assets", "BaseOperateLog": "Operate Log", @@ -651,8 +651,8 @@ "JobCenter": "Job center", "JobCreate": "Create job", "JobDetail": "Job details", - "JobExecutionLog": "Job logs", - "JobManagement": "Jobs", + "JobExecutionLog": "Execution record", + "JobManagement": "Job List", "JobUpdate": "Update the job", "KingSoftCloud": "KingSoft cloud", "KokoSetting": "KoKo", @@ -1410,5 +1410,8 @@ "disallowSelfUpdateFields": "Not allowed to modify the current fields yourself", "forceEnableMFAHelpText": "If force enable, user can not disable by themselves", "removeWarningMsg": "Are you sure you want to remove", - "setVariable": "Set variable" + "setVariable": "Set variable", + "JobsAudit": "Jobs audit", + "JobList": "Job List", + "StopJobMsg": "Stop job successfully" } \ No newline at end of file diff --git a/apps/i18n/lina/ja.json b/apps/i18n/lina/ja.json index 153603970..a9b39e829 100644 --- a/apps/i18n/lina/ja.json +++ b/apps/i18n/lina/ja.json @@ -199,7 +199,7 @@ "BaseCommandFilterAclList": "コマンドフィルタ", "BaseConnectMethodACL": "接続方法の承認", "BaseFlowSetUp": "フロー設定", - "BaseJobManagement": "作業管理", + "BaseJobManagement": "作業列表", "BaseLoginLog": "ログインログ", "BaseMyAssets": "私の資産", "BaseOperateLog": "Actionログ", @@ -509,7 +509,7 @@ "Execute": "実行", "ExecuteOnce": "一度実行する", "ExecutionDetail": "Action詳細", - "ExecutionList": "実行リスト", + "ExecutionList": "実行記録", "ExistError": "この要素は既に存在します", "Existing": "既に存在しています", "ExpirationTimeout": "有効期限タイムアウト(秒)", @@ -669,8 +669,8 @@ "JobCenter": "Actionセンター", "JobCreate": "ジョブ作成", "JobDetail": "作業詳細", - "JobExecutionLog": "作業ログ", - "JobManagement": "作業管理", + "JobExecutionLog": "実行記録", + "JobManagement": "作業列表", "JobUpdate": "アップデート作業", "KingSoftCloud": "Kingsoftクラウド", "KokoSetting": "KoKo 設定", @@ -1268,7 +1268,7 @@ "TemplateAdd": "テンプレート追加", "TemplateCreate": "テンプレート作成", "TemplateHelpText": "テンプレートを選択して追加すると、資産の下に存在しないアカウントが自動的に作成され、プッシュされます", - "TemplateManagement": "テンプレート管理", + "TemplateManagement": "テンプレート一覧", "TencentCloud": "テンセントクラウド", "Terminal": "コンポーネント設定", "TerminalDetail": "コンポーネントの詳細", diff --git a/apps/i18n/lina/zh.json b/apps/i18n/lina/zh.json index fe203f917..7ee0f5450 100644 --- a/apps/i18n/lina/zh.json +++ b/apps/i18n/lina/zh.json @@ -200,7 +200,7 @@ "BaseCommandFilterAclList": "命令过滤", "BaseConnectMethodACL": "连接方式授权", "BaseFlowSetUp": "流程设置", - "BaseJobManagement": "作业管理", + "BaseJobManagement": "作业列表", "BaseLoginLog": "登录日志", "BaseMyAssets": "我的资产", "BaseOperateLog": "操作日志", @@ -497,7 +497,7 @@ "ExecuteAfterSaving": "保存后执行", "ExecuteOnce": "执行一次", "ExecutionDetail": "执行详情", - "ExecutionList": "执行列表", + "ExecutionList": "执行记录", "ExistError": "这个元素已经存在", "Existing": "已存在", "ExpirationTimeout": "过期超时时间(秒)", @@ -655,8 +655,8 @@ "JobCenter": "作业中心", "JobCreate": "创建作业", "JobDetail": "作业详情", - "JobExecutionLog": "作业日志", - "JobManagement": "作业管理", + "JobExecutionLog": "执行记录", + "JobManagement": "作业列表", "JobUpdate": "更新作业", "KingSoftCloud": "金山云", "KokoSetting": "KoKo 配置", @@ -1236,7 +1236,7 @@ "TemplateAdd": "模版添加", "TemplateCreate": "创建模版", "TemplateHelpText": "选择模版添加时,会自动创建资产下不存在的账号并推送", - "TemplateManagement": "模版管理", + "TemplateManagement": "模版列表", "Templates": "模板", "TencentCloud": "腾讯云", "Terminal": "组件设置", @@ -1415,5 +1415,8 @@ "disallowSelfUpdateFields": "不允许自己修改当前字段", "forceEnableMFAHelpText": "如果强制启用,用户无法自行禁用", "removeWarningMsg": "你确定要移除", - "setVariable": "设置参数" + "setVariable": "设置参数", + "JobsAudit": "作业审计", + "JobList": "作业列表", + "StopJobMsg": "停止成功" } \ No newline at end of file diff --git a/apps/i18n/lina/zh_hant.json b/apps/i18n/lina/zh_hant.json index 3bb7fbf95..bd30b6511 100644 --- a/apps/i18n/lina/zh_hant.json +++ b/apps/i18n/lina/zh_hant.json @@ -260,7 +260,7 @@ "BaseCommandFilterAclList": "命令過濾", "BaseConnectMethodACL": "連接方式授權", "BaseFlowSetUp": "流程設定", - "BaseJobManagement": "作業", + "BaseJobManagement": "作業列表", "BaseLoginLog": "登入日誌", "BaseMyAssets": "我的資產", "BaseOperateLog": "操作日誌", @@ -654,7 +654,7 @@ "ExecuteOnce": "執行一次", "Execution": "執行歷史", "ExecutionDetail": "執行詳情", - "ExecutionList": "執行列表", + "ExecutionList": "執行記錄", "ExecutionTimes": "執行次數", "ExistError": "這個元素已經存在", "Existing": "已存在", @@ -846,9 +846,9 @@ "JobCenter": "作業中心", "JobCreate": "創建作業", "JobDetail": "作業詳情", - "JobExecutionLog": "作業日誌", + "JobExecutionLog": "執行記錄", "JobList": "作業管理", - "JobManagement": "作業", + "JobManagement": "作業列表", "JobName": "作業名稱", "JobType": "作業類型", "JobUpdate": "更新作業", @@ -1610,14 +1610,14 @@ "TempPassword": "臨時密碼有效期為 300 秒,使用後立刻失效", "TempPasswordTip": "臨時密碼有效時間為 300 秒,使用後立即失效", "TempToken": "臨時密碼", - "Template": "模板管理", + "Template": "模板列表", "TemplateAdd": "模板添加", "TemplateCreate": "創建模板", "TemplateDetail": "模板詳情", "TemplateHelpText": "選擇模板添加時,會自動創建資產下不存在的帳號並推送", - "TemplateManagement": "模板管理", + "TemplateManagement": "模版列表", "TemplateUpdate": "更新模板", - "Templates": "模板管理", + "Templates": "模板列表", "TencentCloud": "騰訊雲", "Terminal": "組件設置", "TerminalDetail": "組件詳情", diff --git a/apps/ops/api/job.py b/apps/ops/api/job.py index 3322124ca..04b2c6bd8 100644 --- a/apps/ops/api/job.py +++ b/apps/ops/api/job.py @@ -225,7 +225,11 @@ class JobExecutionViewSet(OrgBulkModelViewSet): return Response({'error': serializer.errors}, status=400) task_id = serializer.validated_data['task_id'] try: - instance = get_object_or_404(JobExecution, pk=task_id, creator=request.user) + user = request.user + if user.has_perm("audits.view_joblog"): + instance = get_object_or_404(JobExecution, pk=task_id) + else: + instance = get_object_or_404(JobExecution, pk=task_id, creator=request.user) except Http404: return Response( {'error': _('The task is being created and cannot be interrupted. Please try again later.')}, diff --git a/apps/ops/serializers/job.py b/apps/ops/serializers/job.py index fd4b28aef..555532261 100644 --- a/apps/ops/serializers/job.py +++ b/apps/ops/serializers/job.py @@ -42,7 +42,7 @@ class JobSerializer(BulkOrgResourceModelSerializer, PeriodTaskSerializerMixin, W model = Job read_only_fields = [ "id", "date_last_run", "date_created", - "date_updated", "average_time_cost" + "date_updated", "average_time_cost", "created_by", "material" ] fields_m2m = ['variable'] fields = read_only_fields + [ diff --git a/apps/ops/serializers/variable.py b/apps/ops/serializers/variable.py index 4fb2413bf..a4cdaf9f9 100644 --- a/apps/ops/serializers/variable.py +++ b/apps/ops/serializers/variable.py @@ -101,6 +101,8 @@ class VariableFormDataSerializer(serializers.Serializer): 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') diff --git a/apps/ops/utils.py b/apps/ops/utils.py index 2e970b4d9..b42b1c8a0 100644 --- a/apps/ops/utils.py +++ b/apps/ops/utils.py @@ -45,6 +45,6 @@ def merge_nodes_and_assets(nodes, assets, user): elif node_id == PermNode.UNGROUPED_NODE_KEY: node_assets = perm_util.get_ungroup_assets() else: - _, node_assets = perm_util.get_node_all_assets(node_id) + node, node_assets = perm_util.get_node_all_assets(node_id) assets.extend(node_assets.exclude(id__in=[asset.id for asset in assets])) return assets