feat: 支持批量发送文件

pull/12300/head
wangruidong 2023-12-05 19:09:17 +08:00 committed by Bryan
parent e3ac26e377
commit d0b0c87d3c
11 changed files with 186 additions and 91 deletions

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5d443763c06877304dca8dac76131271287acc6594df665bdf9445455c5187f1
size 167791
oid sha256:a00c0d53df7fa88fc2fe69adda31fd9ab581b5a0362a01b8191924f74fab800d
size 167820

View File

@ -8,8 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-12-08 14:51+0800\n"
"POT-Creation-Date: 2023-12-08 15:33+0800\n"
"POT-Creation-Date: 2023-12-11 14:54+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -88,7 +87,7 @@ msgstr "集めました"
msgid "Template"
msgstr "テンプレート"
#: accounts/const/account.py:31 ops/const.py:45
#: accounts/const/account.py:31 ops/const.py:46
msgid "Skip"
msgstr "スキップ"
@ -100,7 +99,7 @@ msgstr "更新"
#: accounts/const/account.py:33
#: accounts/serializers/automations/change_secret.py:150 audits/const.py:62
#: audits/signal_handlers/activity_log.py:33 common/const/choices.py:19
#: ops/const.py:74 terminal/const.py:79 xpack/plugins/cloud/const.py:46
#: ops/const.py:75 terminal/const.py:79 xpack/plugins/cloud/const.py:46
msgid "Failed"
msgstr "失敗しました"
@ -208,7 +207,6 @@ msgstr "作成のみ"
msgid "Email"
msgstr "メール"
#: accounts/const/automation.py:104 terminal/const.py:87
#: accounts/const/automation.py:105 terminal/const.py:87
msgid "SFTP"
msgstr "SFTP"
@ -265,7 +263,7 @@ msgstr "資産"
#: accounts/models/account.py:53 accounts/models/template.py:16
#: accounts/serializers/account/account.py:220
#: accounts/serializers/account/account.py:268
#: accounts/serializers/account/template.py:25
#: accounts/serializers/account/template.py:27
#: authentication/serializers/connect_token_secret.py:50
msgid "Su from"
msgstr "から切り替え"
@ -397,7 +395,7 @@ msgstr "理由"
#: accounts/models/automations/backup_account.py:135
#: accounts/serializers/automations/change_secret.py:105
#: accounts/serializers/automations/change_secret.py:128
#: ops/serializers/job.py:55 terminal/serializers/session.py:49
#: ops/serializers/job.py:65 terminal/serializers/session.py:49
msgid "Is success"
msgstr "成功は"
@ -585,7 +583,7 @@ msgstr "ひみつ"
msgid "Secret strategy"
msgstr "鍵ポリシー"
#: accounts/models/base.py:44 accounts/serializers/account/template.py:22
#: accounts/models/base.py:44 accounts/serializers/account/template.py:24
#: accounts/serializers/automations/change_secret.py:44
msgid "Password rules"
msgstr "パスワードルール"
@ -902,19 +900,19 @@ msgstr "数値#スウスウ#"
msgid "Special symbol"
msgstr "特殊記号"
#: accounts/serializers/account/template.py:18
#: accounts/serializers/account/template.py:19
msgid "Exclude symbol"
msgstr "除外文字"
#: accounts/serializers/account/template.py:36
#: accounts/serializers/account/template.py:38
msgid "Secret generation strategy for account creation"
msgstr "账号创建时,密文生成策略"
#: accounts/serializers/account/template.py:37
#: accounts/serializers/account/template.py:39
msgid "Whether to automatically push the account to the asset"
msgstr "是否自动推送账号到资产"
#: accounts/serializers/account/template.py:40
#: accounts/serializers/account/template.py:42
msgid ""
"Associated platform, you can configure push parameters. If not associated, "
"default parameters will be used"
@ -980,7 +978,7 @@ msgstr "自動タスク実行履歴"
#: accounts/serializers/automations/change_secret.py:149 audits/const.py:61
#: audits/models.py:64 audits/signal_handlers/activity_log.py:33
#: common/const/choices.py:18 ops/const.py:72 ops/serializers/celery.py:40
#: common/const/choices.py:18 ops/const.py:73 ops/serializers/celery.py:40
#: terminal/const.py:78 terminal/models/session/sharing.py:121
#: tickets/views/approve.py:117
msgid "Success"
@ -1118,7 +1116,7 @@ msgid "Accounts"
msgstr "アカウント"
#: acls/models/command_acl.py:16 assets/models/cmd_filter.py:60
#: ops/serializers/job.py:54 terminal/const.py:86
#: ops/serializers/job.py:64 terminal/const.py:86
#: terminal/models/session/session.py:42 terminal/serializers/command.py:18
#: terminal/templates/terminal/_msg_command_alert.html:12
#: terminal/templates/terminal/_msg_command_execute_alert.html:10
@ -1668,7 +1666,7 @@ msgstr "プロトコル"
msgid "Sudo"
msgstr "すど"
#: assets/models/_user.py:55 ops/const.py:49 ops/const.py:59
#: assets/models/_user.py:55 ops/const.py:50 ops/const.py:60
msgid "Shell"
msgstr "シェル"
@ -3639,7 +3637,7 @@ msgstr "の準備を"
msgid "Pending"
msgstr "未定"
#: common/const/choices.py:17 ops/const.py:71
#: common/const/choices.py:17 ops/const.py:72
msgid "Running"
msgstr "ランニング"
@ -4053,6 +4051,10 @@ msgstr "タスクは存在しません"
msgid "Task {} args or kwargs error"
msgstr "タスク実行パラメータエラー"
#: ops/api/job.py:128
msgid "Duplicate file exists"
msgstr "重複したファイルが存在する"
#: ops/api/playbook.py:39
msgid "Currently playbook is being used in a job"
msgstr "現在プレイブックは1つのジョブで使用されています"
@ -4125,47 +4127,53 @@ msgstr "コマンド#コマンド#"
msgid "Playbook"
msgstr "Playbook"
#: ops/const.py:43
#: ops/const.py:40
#, fuzzy
#| msgid "Upload"
msgid "Upload File"
msgstr "アップロード"
#: ops/const.py:44
msgid "Privileged Only"
msgstr "特権アカウントのみ"
#: ops/const.py:44
#: ops/const.py:45
msgid "Privileged First"
msgstr "特権アカウント優先"
#: ops/const.py:50 ops/const.py:60
#: ops/const.py:51 ops/const.py:61
msgid "Powershell"
msgstr "PowerShell"
#: ops/const.py:51 ops/const.py:61
#: ops/const.py:52 ops/const.py:62
msgid "Python"
msgstr "Python"
#: ops/const.py:52 ops/const.py:62
#: ops/const.py:53 ops/const.py:63
msgid "MySQL"
msgstr "MySQL"
#: ops/const.py:53 ops/const.py:64
#: ops/const.py:54 ops/const.py:65
msgid "PostgreSQL"
msgstr "PostgreSQL"
#: ops/const.py:54 ops/const.py:65
#: ops/const.py:55 ops/const.py:66
msgid "SQLServer"
msgstr "SQLServer"
#: ops/const.py:55 ops/const.py:67
#: ops/const.py:56 ops/const.py:68
msgid "Raw"
msgstr ""
#: ops/const.py:63
#: ops/const.py:64
msgid "MariaDB"
msgstr "MariaDB"
#: ops/const.py:66
#: ops/const.py:67
msgid "Oracle"
msgstr "Oracle"
#: ops/const.py:73
#: ops/const.py:74
msgid "Timeout"
msgstr "タイムアウト"
@ -4299,7 +4307,7 @@ msgstr "Material"
msgid "Material Type"
msgstr "Material を選択してオプションを設定します。"
#: ops/models/job.py:557
#: ops/models/job.py:565
msgid "Job Execution"
msgstr "ジョブ実行"
@ -4343,15 +4351,15 @@ msgstr "{max_threshold} を超えるCPUロード: => {value}"
msgid "Run after save"
msgstr "保存後に実行"
#: ops/serializers/job.py:53
#: ops/serializers/job.py:63
msgid "Job type"
msgstr "タスクの種類"
#: ops/serializers/job.py:56 terminal/serializers/session.py:53
#: ops/serializers/job.py:66 terminal/serializers/session.py:53
msgid "Is finished"
msgstr "終了しました"
#: ops/serializers/job.py:57
#: ops/serializers/job.py:67
msgid "Time cost"
msgstr "時を過ごす"
@ -4567,7 +4575,8 @@ msgstr "認定アカウント"
msgid "today"
msgstr "今日"
#: perms/notifications.py:12 settings/serializers/feature.py:106
#: perms/notifications.py:12 perms/notifications.py:44
#: settings/serializers/feature.py:106
msgid "day"
msgstr "日"
@ -4595,8 +4604,9 @@ msgstr "アセット認証ルールの有効期限が切れていることを確
msgid "Send asset permission expired notification"
msgstr "アセット許可の有効期限通知を送信する"
#: perms/templates/perms/_msg_item_permissions_expire.html:7
#: perms/templates/perms/_msg_permed_items_expire.html:7
#, python-format
msgid ""
"\n"
" The following %(item_type)s will expire in %(count)s\n"

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:8976c6b41e2c0ce591b2b257fd0352b4ed7517661f7df83ba74b302b8cf94b00
size 137479
oid sha256:d4a9a61bf1b247d3843001737ebfa6d5f8580f2d9c1ae0fc76649ecc535f5d96
size 137563

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: JumpServer 0.3.3\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-12-08 15:33+0800\n"
"POT-Creation-Date: 2023-12-11 14:54+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"
@ -86,7 +86,7 @@ msgstr "收集"
msgid "Template"
msgstr "模板"
#: accounts/const/account.py:31 ops/const.py:45
#: accounts/const/account.py:31 ops/const.py:46
msgid "Skip"
msgstr "跳过"
@ -98,7 +98,7 @@ msgstr "更新"
#: accounts/const/account.py:33
#: accounts/serializers/automations/change_secret.py:150 audits/const.py:62
#: audits/signal_handlers/activity_log.py:33 common/const/choices.py:19
#: ops/const.py:74 terminal/const.py:79 xpack/plugins/cloud/const.py:46
#: ops/const.py:75 terminal/const.py:79 xpack/plugins/cloud/const.py:46
msgid "Failed"
msgstr "失败"
@ -262,7 +262,7 @@ msgstr "资产"
#: accounts/models/account.py:53 accounts/models/template.py:16
#: accounts/serializers/account/account.py:220
#: accounts/serializers/account/account.py:268
#: accounts/serializers/account/template.py:25
#: accounts/serializers/account/template.py:27
#: authentication/serializers/connect_token_secret.py:50
msgid "Su from"
msgstr "切换自"
@ -394,7 +394,7 @@ msgstr "原因"
#: accounts/models/automations/backup_account.py:135
#: accounts/serializers/automations/change_secret.py:105
#: accounts/serializers/automations/change_secret.py:128
#: ops/serializers/job.py:55 terminal/serializers/session.py:49
#: ops/serializers/job.py:65 terminal/serializers/session.py:49
msgid "Is success"
msgstr "是否成功"
@ -582,7 +582,7 @@ msgstr "密钥"
msgid "Secret strategy"
msgstr "密文策略"
#: accounts/models/base.py:44 accounts/serializers/account/template.py:22
#: accounts/models/base.py:44 accounts/serializers/account/template.py:24
#: accounts/serializers/automations/change_secret.py:44
msgid "Password rules"
msgstr "密码规则"
@ -898,19 +898,19 @@ msgstr "数字"
msgid "Special symbol"
msgstr "特殊字符"
#: accounts/serializers/account/template.py:18
#: accounts/serializers/account/template.py:19
msgid "Exclude symbol"
msgstr "排除字符"
#: accounts/serializers/account/template.py:36
#: accounts/serializers/account/template.py:38
msgid "Secret generation strategy for account creation"
msgstr "密码生成策略,用于账号创建时,设置密码"
#: accounts/serializers/account/template.py:37
#: accounts/serializers/account/template.py:39
msgid "Whether to automatically push the account to the asset"
msgstr "是否自动推送账号到资产"
#: accounts/serializers/account/template.py:40
#: accounts/serializers/account/template.py:42
msgid ""
"Associated platform, you can configure push parameters. If not associated, "
"default parameters will be used"
@ -975,7 +975,7 @@ msgstr "自动化任务执行历史"
#: accounts/serializers/automations/change_secret.py:149 audits/const.py:61
#: audits/models.py:64 audits/signal_handlers/activity_log.py:33
#: common/const/choices.py:18 ops/const.py:72 ops/serializers/celery.py:40
#: common/const/choices.py:18 ops/const.py:73 ops/serializers/celery.py:40
#: terminal/const.py:78 terminal/models/session/sharing.py:121
#: tickets/views/approve.py:117
msgid "Success"
@ -1113,7 +1113,7 @@ msgid "Accounts"
msgstr "账号管理"
#: acls/models/command_acl.py:16 assets/models/cmd_filter.py:60
#: ops/serializers/job.py:54 terminal/const.py:86
#: ops/serializers/job.py:64 terminal/const.py:86
#: terminal/models/session/session.py:42 terminal/serializers/command.py:18
#: terminal/templates/terminal/_msg_command_alert.html:12
#: terminal/templates/terminal/_msg_command_execute_alert.html:10
@ -1659,7 +1659,7 @@ msgstr "协议"
msgid "Sudo"
msgstr "Sudo"
#: assets/models/_user.py:55 ops/const.py:49 ops/const.py:59
#: assets/models/_user.py:55 ops/const.py:50 ops/const.py:60
msgid "Shell"
msgstr "Shell"
@ -3594,7 +3594,7 @@ msgstr "准备"
msgid "Pending"
msgstr "待定的"
#: common/const/choices.py:17 ops/const.py:71
#: common/const/choices.py:17 ops/const.py:72
msgid "Running"
msgstr "运行中"
@ -4003,6 +4003,10 @@ msgstr "任务 {} 不存在"
msgid "Task {} args or kwargs error"
msgstr "任务 {} 执行参数错误"
#: ops/api/job.py:128
msgid "Duplicate file exists"
msgstr "存在同名文件"
#: ops/api/playbook.py:39
msgid "Currently playbook is being used in a job"
msgstr "当前 playbook 正在作业中使用"
@ -4075,47 +4079,51 @@ msgstr "命令"
msgid "Playbook"
msgstr "Playbook"
#: ops/const.py:43
#: ops/const.py:40
msgid "Upload File"
msgstr "上传"
#: ops/const.py:44
msgid "Privileged Only"
msgstr "仅限特权账号"
#: ops/const.py:44
#: ops/const.py:45
msgid "Privileged First"
msgstr "特权账号优先"
#: ops/const.py:50 ops/const.py:60
#: ops/const.py:51 ops/const.py:61
msgid "Powershell"
msgstr "PowerShell"
#: ops/const.py:51 ops/const.py:61
#: ops/const.py:52 ops/const.py:62
msgid "Python"
msgstr "Python"
#: ops/const.py:52 ops/const.py:62
#: ops/const.py:53 ops/const.py:63
msgid "MySQL"
msgstr "MySQL"
#: ops/const.py:53 ops/const.py:64
#: ops/const.py:54 ops/const.py:65
msgid "PostgreSQL"
msgstr "PostgreSQL"
#: ops/const.py:54 ops/const.py:65
#: ops/const.py:55 ops/const.py:66
msgid "SQLServer"
msgstr "SQLServer"
#: ops/const.py:55 ops/const.py:67
#: ops/const.py:56 ops/const.py:68
msgid "Raw"
msgstr "Raw"
#: ops/const.py:63
#: ops/const.py:64
msgid "MariaDB"
msgstr "MariaDB"
#: ops/const.py:66
#: ops/const.py:67
msgid "Oracle"
msgstr "Oracle"
#: ops/const.py:73
#: ops/const.py:74
msgid "Timeout"
msgstr "超时"
@ -4249,7 +4257,7 @@ msgstr "Material"
msgid "Material Type"
msgstr "Material 类型"
#: ops/models/job.py:557
#: ops/models/job.py:565
msgid "Job Execution"
msgstr "作业执行"
@ -4293,15 +4301,15 @@ msgstr "CPU 使用率超过 {max_threshold}: => {value}"
msgid "Run after save"
msgstr "保存后执行"
#: ops/serializers/job.py:53
#: ops/serializers/job.py:63
msgid "Job type"
msgstr "任务类型"
#: ops/serializers/job.py:56 terminal/serializers/session.py:53
#: ops/serializers/job.py:66 terminal/serializers/session.py:53
msgid "Is finished"
msgstr "是否完成"
#: ops/serializers/job.py:57
#: ops/serializers/job.py:67
msgid "Time cost"
msgstr "花费时间"
@ -4516,7 +4524,8 @@ msgstr "授权账号"
msgid "today"
msgstr "今天"
#: perms/notifications.py:12 settings/serializers/feature.py:106
#: perms/notifications.py:12 perms/notifications.py:44
#: settings/serializers/feature.py:106
msgid "day"
msgstr "天"
@ -4545,20 +4554,6 @@ msgid "Send asset permission expired notification"
msgstr "发送资产权限过期通知"
#: perms/templates/perms/_msg_item_permissions_expire.html:7
#, fuzzy, python-format
#| msgid ""
#| "\n"
#| " The following %(item_type)s will expire in %(count)s\n"
#| " "
msgid ""
"\n"
" The following %(item_type)s will expire in %(count)s days\n"
" "
msgstr ""
"\n"
" 以下 %(item_type)s 即将在 %(count)s 后过期\n"
" "
#: perms/templates/perms/_msg_permed_items_expire.html:7
#, python-format
msgid ""
@ -8801,6 +8796,7 @@ msgstr "企业专业版"
msgid "Ultimate edition"
msgstr "企业旗舰版"
#~ msgid "FeiShu query user failed"
#~ msgstr "飞书查询用户失败"

View File

@ -1,8 +1,9 @@
import os
import uuid
import shutil
import ansible_runner
from django.conf import settings
from django.utils._os import safe_join
from .callback import DefaultCallback
from ..utils import get_ansible_log_verbosity
@ -85,6 +86,34 @@ class PlaybookRunner:
return self.cb
class UploadFileRunner:
def __init__(self, inventory, job_id, dest_path, callback=None):
self.id = uuid.uuid4()
self.inventory = inventory
self.cb = DefaultCallback()
upload_file_dir = safe_join(settings.DATA_DIR, 'job_upload_file')
self.src_paths = safe_join(upload_file_dir, str(job_id))
self.dest_path = dest_path
def run(self, verbosity=0, **kwargs):
verbosity = get_ansible_log_verbosity(verbosity)
ansible_runner.run(
host_pattern="*",
inventory=self.inventory,
module='copy',
module_args=f"src={self.src_paths}/ dest={self.dest_path}",
verbosity=verbosity,
event_handler=self.cb.event_handler,
status_handler=self.cb.status_handler,
**kwargs
)
try:
shutil.rmtree(self.src_paths)
except OSError as e:
print(f"del upload tmp dir {self.src_paths} failed! {e}")
return self.cb
class CommandRunner(AdHocRunner):
def __init__(self, inventory, command, pattern='*', project_dir='/tmp/'):
super().__init__(inventory, 'shell', command, pattern, project_dir)

View File

@ -1,16 +1,22 @@
import json
import os
from django.conf import settings
from django.db import transaction
from django.db.models import Count
from django.db.transaction import atomic
from django.shortcuts import get_object_or_404
from django.utils._os import safe_join
from django.utils.translation import gettext_lazy as _
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.views import APIView
from assets.models import Asset
from common.const.http import POST
from common.permissions import IsValidUser
from ops.const import Types
from ops.models import Job, JobExecution
from ops.serializers.job import JobSerializer, JobExecutionSerializer
from ops.serializers.job import JobSerializer, JobExecutionSerializer, FileSerializer
__all__ = [
'JobViewSet', 'JobExecutionViewSet', 'JobRunVariableHelpAPIView',
@ -24,6 +30,7 @@ from orgs.utils import tmp_to_org, get_current_org
from accounts.models import Account
from perms.models import PermNode
from perms.utils import UserPermAssetUtil
from jumpserver.settings import get_file_md5
def set_task_to_serializer_data(serializer, task_id):
@ -91,6 +98,40 @@ class JobViewSet(OrgBulkModelViewSet):
transaction.on_commit(
lambda: run_ops_job_execution.apply_async((str(execution.id),), task_id=str(execution.id)))
@action(methods=[POST], detail=False, serializer_class=FileSerializer, permission_classes=[IsValidUser, ],
url_path='upload')
def upload(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
if not serializer.is_valid():
msg = 'Upload data invalid: {}'.format(serializer.errors)
return Response({'msg': msg}, status=400)
uploaded_files = request.FILES.getlist('files')
job_id = request.data.get('job_id', '')
job = get_object_or_404(Job, pk=job_id)
job_args = json.loads(job.args)
src_path_info = []
filename_set = set()
same_filenames = []
upload_file_dir = safe_join(settings.DATA_DIR, 'job_upload_file')
for uploaded_file in uploaded_files:
filename = uploaded_file.name
saved_path = safe_join(upload_file_dir, f'{job_id}/{filename}')
os.makedirs(os.path.dirname(saved_path), exist_ok=True)
with open(saved_path, 'wb+') as destination:
for chunk in uploaded_file.chunks():
destination.write(chunk)
if filename in filename_set:
same_filenames.append(filename)
filename_set.add(filename)
src_path_info.append({'filename': filename, 'md5': get_file_md5(saved_path)})
if same_filenames:
return Response({'msg': _("Duplicate file exists")}, status=400)
job_args['src_path_info'] = src_path_info
job.args = json.dumps(job_args)
job.save()
self.run_job(job, serializer)
return Response({'task_id': serializer.data.get('task_id')}, status=201)
class JobExecutionViewSet(OrgBulkModelViewSet):
serializer_class = JobExecutionSerializer

View File

@ -37,6 +37,7 @@ class CreateMethods(models.TextChoices):
class Types(models.TextChoices):
adhoc = 'adhoc', _('Adhoc')
playbook = 'playbook', _('Playbook')
upload_file = 'upload_file', _('Upload File')
class RunasPolicies(models.TextChoices):

View File

@ -23,7 +23,7 @@ from assets.models import Asset
from assets.automations.base.manager import SSHTunnelManager
from common.db.encoder import ModelJSONFieldEncoder
from labels.mixins import LabeledMixin
from ops.ansible import JMSInventory, AdHocRunner, PlaybookRunner, CommandInBlackListException
from ops.ansible import JMSInventory, AdHocRunner, PlaybookRunner, CommandInBlackListException, UploadFileRunner
from ops.mixin import PeriodTaskModelMixin
from ops.variables import *
from ops.const import Types, RunasPolicies, JobStatus, JobModules
@ -362,7 +362,7 @@ class JobExecution(JMSOrgBaseModel):
static_variables = self.gather_static_variables()
extra_vars.update(static_variables)
if self.current_job.type == 'adhoc':
if self.current_job.type == Types.adhoc:
module, args = self.compile_shell()
runner = AdHocRunner(
@ -374,10 +374,18 @@ class JobExecution(JMSOrgBaseModel):
project_dir=self.private_dir,
extra_vars=extra_vars,
)
elif self.current_job.type == 'playbook':
elif self.current_job.type == Types.playbook:
runner = PlaybookRunner(
self.inventory_path, self.current_job.playbook.entry
)
elif self.current_job.type == Types.upload_file:
job_id = self.current_job.id
args = json.loads(self.current_job.args)
dst_path = args.get('dst_path')
if dst_path:
runner = UploadFileRunner(self.inventory_path, job_id, dst_path)
else:
raise ValueError("dst_path is null")
else:
raise Exception("unsupported job type")
return runner

View File

@ -21,9 +21,12 @@ class JobSerializer(ResourceLabelsMixin, BulkOrgResourceModelSerializer, PeriodT
def to_internal_value(self, data):
instant = data.get('instant', False)
job_type = data.get('type', '')
_uid = str(uuid.uuid4()).split('-')[-1]
if instant:
_uid = str(uuid.uuid4()).split('-')[-1]
data['name'] = f'job-{_uid}'
if job_type == 'upload_file':
data['name'] = f'upload_file-{_uid}'
return super().to_internal_value(data)
def get_request_user(self):
@ -44,10 +47,17 @@ class JobSerializer(ResourceLabelsMixin, BulkOrgResourceModelSerializer, PeriodT
"use_parameter_define", "parameters_define",
"timeout", "chdir", "comment", "summary",
"is_periodic", "interval", "crontab", "nodes",
"run_after_save",
"run_after_save"
]
class FileSerializer(serializers.Serializer):
files = serializers.FileField(allow_empty_file=True)
class Meta:
ref_name = "JobFileSerializer"
class JobExecutionSerializer(BulkOrgResourceModelSerializer):
creator = ReadableHiddenField(default=serializers.CurrentUserDefault())
job_type = serializers.ReadOnlyField(label=_("Job type"))

View File

@ -41,7 +41,7 @@ class AssetPermsWillExpireForOrgAdminMsg(UserMessage):
super().__init__(user)
self.perms = perms
self.org = org
self.day_count = _('today') if day_count == 0 else day_count
self.day_count = _('today') if day_count == 0 else day_count + _('day')
def get_items_with_url(self):
items_with_url = []

View File

@ -5,7 +5,7 @@
<p>
{% blocktranslate %}
The following {{ item_type }} will expire in {{ count }} days
The following {{ item_type }} will expire in {{ count }}
{% endblocktranslate %}
</p>