diff --git a/apps/assets/forms/asset.py b/apps/assets/forms/asset.py index 1ec2ea24f..0a6b2f093 100644 --- a/apps/assets/forms/asset.py +++ b/apps/assets/forms/asset.py @@ -41,9 +41,6 @@ class AssetCreateForm(OrgModelForm): 'nodes': _("Node"), } help_texts = { - 'hostname': '* required', - 'ip': '* required', - 'port': '* required', 'admin_user': _( 'root or other NOPASSWD sudo privilege user existed in asset,' 'If asset is windows or other set any one, more see admin user left menu' @@ -80,10 +77,6 @@ class AssetUpdateForm(OrgModelForm): 'nodes': _("Node"), } help_texts = { - 'hostname': '* required', - 'ip': '* required', - 'port': '* required', - 'cluster': '* required', 'admin_user': _( 'root or other NOPASSWD sudo privilege user existed in asset,' 'If asset is windows or other set any one, more see admin user left menu' @@ -95,7 +88,7 @@ class AssetUpdateForm(OrgModelForm): class AssetBulkUpdateForm(OrgModelForm): assets = forms.ModelMultipleChoiceField( - required=True, help_text='* required', + required=True, label=_('Select assets'), queryset=Asset.objects.all(), widget=forms.SelectMultiple( attrs={ diff --git a/apps/assets/forms/domain.py b/apps/assets/forms/domain.py index 3c733bcc4..635796c97 100644 --- a/apps/assets/forms/domain.py +++ b/apps/assets/forms/domain.py @@ -61,7 +61,3 @@ class GatewayForm(PasswordAndKeyAuthForm, OrgModelForm): 'name': forms.TextInput(attrs={'placeholder': _('Name')}), 'username': forms.TextInput(attrs={'placeholder': _('Username')}), } - help_texts = { - 'name': '* required', - 'username': '* required', - } diff --git a/apps/assets/forms/user.py b/apps/assets/forms/user.py index 81138eab5..575d3e59c 100644 --- a/apps/assets/forms/user.py +++ b/apps/assets/forms/user.py @@ -80,10 +80,6 @@ class AdminUserForm(PasswordAndKeyAuthForm): 'name': forms.TextInput(attrs={'placeholder': _('Name')}), 'username': forms.TextInput(attrs={'placeholder': _('Username')}), } - help_texts = { - 'name': '* required', - 'username': '* required', - } class SystemUserForm(OrgModelForm, PasswordAndKeyAuthForm): @@ -150,7 +146,6 @@ class SystemUserForm(OrgModelForm, PasswordAndKeyAuthForm): }), } help_texts = { - 'name': '* required', 'auto_push': _('Auto push system user to asset'), 'priority': _('1-100, High level will be using login asset as default, ' 'if user was granted more than 2 system user'), diff --git a/apps/common/models.py b/apps/common/models.py index cb97b8988..012cd7351 100644 --- a/apps/common/models.py +++ b/apps/common/models.py @@ -45,10 +45,10 @@ class Setting(models.Model): def cleaned_value(self): try: value = self.value - if not isinstance(value, (str, bytes)): - return value if self.encrypted: value = signer.unsign(value) + if not value: + return None value = json.loads(value) return value except json.JSONDecodeError: diff --git a/apps/common/templates/common/command_storage_create.html b/apps/common/templates/common/command_storage_create.html index a3a83f2e7..671b11c94 100644 --- a/apps/common/templates/common/command_storage_create.html +++ b/apps/common/templates/common/command_storage_create.html @@ -41,7 +41,6 @@
-
* required
diff --git a/apps/common/templates/common/replay_storage_create.html b/apps/common/templates/common/replay_storage_create.html index 8b2ab8596..af56c210d 100644 --- a/apps/common/templates/common/replay_storage_create.html +++ b/apps/common/templates/common/replay_storage_create.html @@ -44,7 +44,6 @@
-
* required
diff --git a/apps/common/tree.py b/apps/common/tree.py index 6b57a3db4..13756a35d 100644 --- a/apps/common/tree.py +++ b/apps/common/tree.py @@ -49,7 +49,9 @@ class TreeNode: return False elif not self.isParent and other.isParent: return True - return self.id > other.id + if self.pId != other.pId: + return self.pId > other.pId + return self.name > other.name def __eq__(self, other): return self.id == other.id diff --git a/apps/jumpserver/conf.py b/apps/jumpserver/conf.py index 8f6a1213f..61fd84249 100644 --- a/apps/jumpserver/conf.py +++ b/apps/jumpserver/conf.py @@ -316,7 +316,7 @@ defaults = { 'EMAIL_SUFFIX': 'jumpserver.org', 'TERMINAL_PASSWORD_AUTH': True, 'TERMINAL_PUBLIC_KEY_AUTH': True, - 'TERMINAL_HEARTBEAT_INTERVAL': 30, + 'TERMINAL_HEARTBEAT_INTERVAL': 20, 'TERMINAL_ASSET_LIST_SORT_BY': 'hostname', 'TERMINAL_ASSET_LIST_PAGE_SIZE': 'auto', 'TERMINAL_SESSION_KEEP_DURATION': 9999, diff --git a/apps/jumpserver/settings.py b/apps/jumpserver/settings.py index 167de3180..ca3d5afa3 100644 --- a/apps/jumpserver/settings.py +++ b/apps/jumpserver/settings.py @@ -499,8 +499,9 @@ BOOTSTRAP3 = { # Field class to use in horizontal forms 'horizontal_field_class': 'col-md-9', # Set placeholder attributes to label if no placeholder is provided - 'set_placeholder': True, + 'set_placeholder': False, 'success_css_class': '', + 'required_css_class': 'required', } TOKEN_EXPIRATION = CONFIG.TOKEN_EXPIRATION diff --git a/apps/ops/models/adhoc.py b/apps/ops/models/adhoc.py index 3e119c98f..cedbbb4ff 100644 --- a/apps/ops/models/adhoc.py +++ b/apps/ops/models/adhoc.py @@ -168,7 +168,10 @@ class AdHoc(models.Model): @property def tasks(self): - return json.loads(self._tasks) + try: + return json.loads(self._tasks) + except: + return [] @tasks.setter def tasks(self, item): diff --git a/apps/ops/templates/ops/adhoc_detail.html b/apps/ops/templates/ops/adhoc_detail.html index abbb16c04..8b340b808 100644 --- a/apps/ops/templates/ops/adhoc_detail.html +++ b/apps/ops/templates/ops/adhoc_detail.html @@ -186,6 +186,19 @@ - {% include 'users/_user_update_pk_modal.html' %} +{% endblock %} +{% block custom_foot_js %} + {% endblock %} diff --git a/apps/ops/templates/ops/adhoc_history_detail.html b/apps/ops/templates/ops/adhoc_history_detail.html index b8a48d4e5..5091470d5 100644 --- a/apps/ops/templates/ops/adhoc_history_detail.html +++ b/apps/ops/templates/ops/adhoc_history_detail.html @@ -19,7 +19,7 @@ {% trans 'Run history detail' %}
  • - {% trans 'Output' %} + {% trans 'Output' %}
  • @@ -141,4 +141,14 @@ {% include 'users/_user_update_pk_modal.html' %} {% endblock %} +{% block custom_foot_js %} + +{% endblock %} diff --git a/apps/ops/templates/ops/task_adhoc.html b/apps/ops/templates/ops/task_adhoc.html index 82c25e667..34e0797e6 100644 --- a/apps/ops/templates/ops/task_adhoc.html +++ b/apps/ops/templates/ops/task_adhoc.html @@ -25,7 +25,7 @@ {% trans 'Run history' %}
  • - {% trans 'Last run output' %} + {% trans 'Last run output' %}
  • @@ -78,52 +78,60 @@ {% endblock %} {% block custom_foot_js %} - + $(td).html(cellData); + }}, + {targets: 2, createdCell: function (td, cellData, rowData) { + var dataLength = cellData.length; + $(td).html(dataLength); + }}, + {targets: 4, createdCell: function (td, cellData) { + if (!cellData) { + $(td).html("Admin") + } else { + $(td).html(cellData) + } + }}, + {targets: 5, createdCell: function (td, cellData, rowData) { + if (!cellData) { + $(td).html("") + } else { + $(td).html(cellData.user) + } + }}, + {targets: 6, createdCell: function (td, cellData) { + var d = new Date(cellData); + $(td).html(d.toLocaleString()) + }}, + {targets: 7, createdCell: function (td, cellData, rowData) { + var detail_btn = '{% trans "Detail" %}'.replace('{{ DEFAULT_PK }}', cellData); + if (cellData) { + $(td).html(detail_btn); + } + }} + ], + ajax_url: '{% url "api-ops:adhoc-list" %}?task={{ object.pk }}', + columns: [{data: function(){return ""}}, {data: "short_id" }, {data: "hosts"}, {data: "pattern"}, + {data: "run_as"}, {data: "become"}, {data: "date_created"}, {data: "id"}] + }; + jumpserver.initDataTable(options); +}).on('click', '.celery-task-log', function () { + var history_pk = "{{ object.latest_history.pk }}"; + if (!history_pk) { + alert("没有运行历史"); + return + } + var url = '{% url 'ops:celery-task-log' pk=DEFAULT_PK %}'.replace('{{ DEFAULT_PK }}', history_pk); + window.open(url, '', 'width=800,height=600,left=400,top=400') +}) + {% endblock %} diff --git a/apps/ops/templates/ops/task_detail.html b/apps/ops/templates/ops/task_detail.html index d8f9520be..bbeaad660 100644 --- a/apps/ops/templates/ops/task_detail.html +++ b/apps/ops/templates/ops/task_detail.html @@ -26,7 +26,7 @@ {% trans 'Run history' %}
  • - {% trans 'Last run output' %} + {% trans 'Last run output' %}
  • @@ -165,4 +165,19 @@ {% endblock %} +{% block custom_foot_js %} + +{% endblock %} diff --git a/apps/ops/templates/ops/task_history.html b/apps/ops/templates/ops/task_history.html index 184987766..9a63acc6a 100644 --- a/apps/ops/templates/ops/task_history.html +++ b/apps/ops/templates/ops/task_history.html @@ -25,7 +25,7 @@ {% trans 'Run history' %}
  • - {% trans 'Last run output' %} + {% trans 'Last run output' %}
  • @@ -148,6 +148,14 @@ function initTable() { $(document).ready(function () { initTable(); +}).on('click', '.celery-task-log', function () { + var history_pk = "{{ object.latest_history.pk }}"; + if (!history_pk) { + alert("没有运行历史"); + return + } + var url = '{% url 'ops:celery-task-log' pk=DEFAULT_PK %}'.replace('{{ DEFAULT_PK }}', history_pk); + window.open(url, '', 'width=800,height=600,left=400,top=400') }) diff --git a/apps/perms/utils.py b/apps/perms/utils.py index ef8e3d09a..45ec6e039 100644 --- a/apps/perms/utils.py +++ b/apps/perms/utils.py @@ -18,8 +18,7 @@ class GenerateTree: "asset_instance": set("system_user") } """ - self.__all_nodes = Node.objects.all() - self.__node_asset_map = defaultdict(set) + self.__all_nodes = list(Node.objects.all()) self.nodes = defaultdict(dict) def add_asset(self, asset, system_users): diff --git a/apps/static/css/jumpserver.css b/apps/static/css/jumpserver.css index 2a6f06e8c..c979678e0 100644 --- a/apps/static/css/jumpserver.css +++ b/apps/static/css/jumpserver.css @@ -438,4 +438,7 @@ div.dataTables_wrapper div.dataTables_filter { white-space: nowrap; } - +.form-group .required .control-label:after { + content:"*"; + color:red; +} diff --git a/apps/users/forms.py b/apps/users/forms.py index fb492412f..521bc13ae 100644 --- a/apps/users/forms.py +++ b/apps/users/forms.py @@ -63,11 +63,6 @@ class UserCreateUpdateForm(OrgModelForm): 'username', 'name', 'email', 'groups', 'wechat', 'phone', 'role', 'date_expired', 'comment', 'otp_level' ] - help_texts = { - 'username': '* required', - 'name': '* required', - 'email': '* required', - } widgets = { 'otp_level': forms.RadioSelect(), 'groups': forms.SelectMultiple( @@ -141,11 +136,6 @@ class UserProfileForm(forms.ModelForm): 'username', 'name', 'email', 'wechat', 'phone', ] - help_texts = { - 'username': '* required', - 'name': '* required', - 'email': '* required', - } UserProfileForm.verbose_name = _("Profile") @@ -263,7 +253,6 @@ UserPublicKeyForm.verbose_name = _("Public key") class UserBulkUpdateForm(OrgModelForm): users = forms.ModelMultipleChoiceField( required=True, - help_text='* required', label=_('Select users'), queryset=User.objects.all(), widget=forms.SelectMultiple( @@ -346,9 +335,6 @@ class UserGroupForm(OrgModelForm): fields = [ 'name', 'users', 'comment', ] - help_texts = { - 'name': '* required' - } class FileForm(forms.Form): diff --git a/config_example.py b/config_example.py index e37df23b0..5f5301f0e 100644 --- a/config_example.py +++ b/config_example.py @@ -78,7 +78,7 @@ class Config: REDIS_HOST = '127.0.0.1' REDIS_PORT = 6379 # REDIS_PASSWORD = '' - # REDIS_DB_CELERY_BROKER = 3 + # REDIS_DB_CELERY = 3 # REDIS_DB_CACHE = 4 # Use OpenID authorization diff --git a/requirements/deb_requirements.txt b/requirements/deb_requirements.txt index 07b3441c4..f32a217e6 100644 --- a/requirements/deb_requirements.txt +++ b/requirements/deb_requirements.txt @@ -1 +1 @@ -libtiff5-dev libjpeg8-dev zlib1g-dev libfreetype6-dev liblcms2-dev libwebp-dev tcl8.5-dev tk8.5-dev python-tk python-dev openssl libssl-dev libldap2-dev libsasl2-dev sqlite libkrb5-dev sshpass +libtiff5-dev libjpeg8-dev zlib1g-dev libfreetype6-dev liblcms2-dev libwebp-dev tcl8.5-dev tk8.5-dev python-tk python-dev openssl libssl-dev libldap2-dev libsasl2-dev sqlite libkrb5-dev sshpass libmysqlclient-dev