diff --git a/apps/assets/serializers/asset.py b/apps/assets/serializers/asset.py index a3661db5c..dae9ab9af 100644 --- a/apps/assets/serializers/asset.py +++ b/apps/assets/serializers/asset.py @@ -4,7 +4,7 @@ from rest_framework import serializers from rest_framework_bulk.serializers import BulkListSerializer from common.mixins import BulkSerializerMixin -from ..models import Asset, Node +from ..models import Asset from .system_user import AssetSystemUserSerializer __all__ = [ diff --git a/apps/assets/urls/api_urls.py b/apps/assets/urls/api_urls.py index ca23a716c..bdbbe5f1d 100644 --- a/apps/assets/urls/api_urls.py +++ b/apps/assets/urls/api_urls.py @@ -5,7 +5,6 @@ from rest_framework_bulk.routes import BulkRouter app_name = 'assets' - router = BulkRouter() router.register(r'assets', api.AssetViewSet, 'asset') router.register(r'admin-user', api.AdminUserViewSet, 'admin-user') diff --git a/apps/common/forms.py b/apps/common/forms.py index 046c64443..00f6af3d2 100644 --- a/apps/common/forms.py +++ b/apps/common/forms.py @@ -197,7 +197,6 @@ class SecuritySettingForm(BaseForm): ) # upper case SECURITY_PASSWORD_UPPER_CASE = forms.BooleanField( - initial=False, required=False, label=_("Must contain capital letters"), help_text=_( diff --git a/apps/common/mixins.py b/apps/common/mixins.py index bb21fe07e..ceeaed6c1 100644 --- a/apps/common/mixins.py +++ b/apps/common/mixins.py @@ -71,19 +71,20 @@ class BulkSerializerMixin(object): ret = super(BulkSerializerMixin, self).to_internal_value(data) id_attr = getattr(self.Meta, 'update_lookup_field', 'id') - request_method = getattr(getattr(self.context.get('view'), 'request'), 'method', '') - # add update_lookup_field field back to validated data - # since super by default strips out read-only fields - # hence id will no longer be present in validated_data - if all((isinstance(self.root, BulkListSerializer), - id_attr, - request_method in ('PUT', 'PATCH'))): - id_field = self.fields[id_attr] - if data.get("id"): - id_value = id_field.to_internal_value(data.get("id")) - else: - id_value = id_field.to_internal_value(data.get("pk")) - ret[id_attr] = id_value + if self.context.get('view'): + request_method = getattr(getattr(self.context.get('view'), 'request'), 'method', '') + # add update_lookup_field field back to validated data + # since super by default strips out read-only fields + # hence id will no longer be present in validated_data + if all((isinstance(self.root, BulkListSerializer), + id_attr, + request_method in ('PUT', 'PATCH'))): + id_field = self.fields[id_attr] + if data.get("id"): + id_value = id_field.to_internal_value(data.get("id")) + else: + id_value = id_field.to_internal_value(data.get("pk")) + ret[id_attr] = id_value return ret diff --git a/apps/jumpserver/settings.py b/apps/jumpserver/settings.py index 0b07bad70..6635b35e6 100644 --- a/apps/jumpserver/settings.py +++ b/apps/jumpserver/settings.py @@ -72,6 +72,7 @@ INSTALLED_APPS = [ 'captcha', 'django_celery_beat', 'django.contrib.auth', + 'django.contrib.admin', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index b6f9a00b4..5da9e7a3c 100644 Binary files a/apps/locale/zh/LC_MESSAGES/django.mo and b/apps/locale/zh/LC_MESSAGES/django.mo differ diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 7895d020e..938b305e7 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Jumpserver 0.3.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-09-04 16:00+0800\n" +"POT-Creation-Date: 2018-09-07 12:00+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: ibuler \n" "Language-Team: Jumpserver team\n" @@ -759,7 +759,7 @@ msgstr "重置" #: common/templates/common/terminal_setting.html:108 #: perms/templates/perms/asset_permission_create_update.html:70 #: terminal/templates/terminal/command_list.html:103 -#: terminal/templates/terminal/session_list.html:126 +#: terminal/templates/terminal/session_list.html:127 #: terminal/templates/terminal/terminal_update.html:48 #: users/templates/users/_user.html:47 #: users/templates/users/forgot_password.html:45 @@ -1759,7 +1759,7 @@ msgid "" "Tip :(unit/minute) if the user has failed to log in for a limited number of " "times, no login is allowed during this time interval." msgstr "" -"提示:(单位 / 分钟)当用户登录失败次数达到限制后,那么在此时间间隔内禁止登录." +"提示: (单位: 分钟) 当用户登录失败次数达到限制后,那么在此时间间隔内禁止登录." #: common/forms.py:187 msgid "Connection max idle time" @@ -1768,47 +1768,47 @@ msgstr "SSH最大空闲时间" #: common/forms.py:189 msgid "" "If idle time more than it, disconnect connection(only ssh now) Unit: minute" -msgstr "如果超过该配置没有操作,连接会被断开" +msgstr "提示: (单位: 分钟) 如果超过该配置没有操作,连接会被断开(仅ssh) " #: common/forms.py:195 msgid "Password minimum length" msgstr "密码最小长度 " -#: common/forms.py:202 +#: common/forms.py:201 msgid "Must contain capital letters" msgstr "必须包含大写字母" -#: common/forms.py:204 +#: common/forms.py:203 msgid "" "After opening, the user password changes and resets must contain uppercase " "letters" msgstr "开启后,用户密码修改、重置必须包含大写字母" -#: common/forms.py:210 +#: common/forms.py:209 msgid "Must contain lowercase letters" msgstr "必须包含小写字母" -#: common/forms.py:211 +#: common/forms.py:210 msgid "" "After opening, the user password changes and resets must contain lowercase " "letters" msgstr "开启后,用户密码修改、重置必须包含小写字母" -#: common/forms.py:217 +#: common/forms.py:216 msgid "Must contain numeric characters" msgstr "必须包含数字字符" -#: common/forms.py:218 +#: common/forms.py:217 msgid "" "After opening, the user password changes and resets must contain numeric " "characters" msgstr "开启后,用户密码修改、重置必须包含数字字符" -#: common/forms.py:224 +#: common/forms.py:223 msgid "Must contain special characters" msgstr "必须包含特殊字符" -#: common/forms.py:225 +#: common/forms.py:224 msgid "" "After opening, the user password changes and resets must contain special " "characters" @@ -2717,10 +2717,20 @@ msgstr "终断" msgid "Terminate selected" msgstr "终断所选" -#: terminal/templates/terminal/session_list.html:142 +#: terminal/templates/terminal/session_list.html:123 +msgid "Confirm finished" +msgstr "确认已完成" + +#: terminal/templates/terminal/session_list.html:143 msgid "Terminate task send, waiting ..." msgstr "终断任务已发送,请等待" +#: terminal/templates/terminal/session_list.html:156 +#, fuzzy +#| msgid "MFA enable success" +msgid "Finish session success" +msgstr "MFA 绑定成功" + #: terminal/templates/terminal/terminal_detail.html:13 #: terminal/views/terminal.py:59 msgid "Terminal detail" @@ -2805,7 +2815,7 @@ msgstr "MFA认证失败" #: users/api/user.py:134 msgid "Could not reset self otp, use profile reset instead" -msgstr "" +msgstr "不能再该页面重置MFA, 请去个人信息页面重置" #: users/authentication.py:56 msgid "Invalid signature header. No credentials provided." diff --git a/apps/static/js/jumpserver.js b/apps/static/js/jumpserver.js index 10e3d5589..bfd94efd4 100644 --- a/apps/static/js/jumpserver.js +++ b/apps/static/js/jumpserver.js @@ -154,8 +154,10 @@ function activeNav() { function APIUpdateAttr(props) { // props = {url: .., body: , success: , error: , method: ,} props = props || {}; - var success_message = props.success_message || gettext('Update is successful!'); - var fail_message = props.fail_message || gettext('An unknown error occurred while updating..'); + var user_success_message = props.success_message; + var default_success_message = gettext('Update is successful!'); + var user_fail_message = props.fail_message; + var default_failed_message = gettext('An unknown error occurred while updating..'); var flash_message = props.flash_message || true; if (props.flash_message === false){ flash_message = false; @@ -169,14 +171,36 @@ function APIUpdateAttr(props) { dataType: props.data_type || "json" }).done(function(data, textStatue, jqXHR) { if (flash_message) { - toastr.success(success_message); + var msg = ""; + if (user_fail_message) { + msg = user_success_message; + } else { + msg = default_success_message; + } + toastr.success(msg); } if (typeof props.success === 'function') { return props.success(data); } }).fail(function(jqXHR, textStatus, errorThrown) { if (flash_message) { - toastr.error(fail_message); + var msg = ""; + console.log(jqXHR); + console.log(textStatus); + console.log(errorThrown); + if (user_fail_message) { + msg = user_fail_message; + } else if (jqXHR.responseJSON) { + if (jqXHR.responseJSON.error) { + msg = jqXHR.responseJSON.error + } else if (jqXHR.responseJSON.msg) { + msg = jqXHR.responseJSON.msg + } + } + if (msg === "") { + msg = default_failed_message; + } + toastr.error(msg); } if (typeof props.error === 'function') { return props.error(jqXHR.responseText, jqXHR.status); diff --git a/apps/terminal/api.py b/apps/terminal/api.py index 0b908d837..1a2a35184 100644 --- a/apps/terminal/api.py +++ b/apps/terminal/api.py @@ -15,6 +15,7 @@ from django.conf import settings import jms_storage +from rest_framework.pagination import LimitOffsetPagination from rest_framework import viewsets from rest_framework.views import APIView, Response from rest_framework.permissions import AllowAny @@ -173,9 +174,10 @@ class StatusViewSet(viewsets.ModelViewSet): return super().get_permissions() -class SessionViewSet(viewsets.ModelViewSet): +class SessionViewSet(BulkModelViewSet): queryset = Session.objects.all() serializer_class = SessionSerializer + pagination_class = LimitOffsetPagination permission_classes = (IsOrgAdminOrAppUser,) def get_queryset(self): @@ -183,7 +185,7 @@ class SessionViewSet(viewsets.ModelViewSet): if terminal_id: terminal = get_object_or_404(Terminal, id=terminal_id) self.queryset = terminal.session_set.all() - return self.queryset + return self.queryset.all() def perform_create(self, serializer): if hasattr(self.request.user, 'terminal'): diff --git a/apps/terminal/serializers.py b/apps/terminal/serializers.py index c18c5023d..425eae8b1 100644 --- a/apps/terminal/serializers.py +++ b/apps/terminal/serializers.py @@ -5,9 +5,7 @@ from django.utils import timezone from rest_framework import serializers from rest_framework_bulk.serializers import BulkListSerializer - from common.mixins import BulkSerializerMixin -from common.utils import get_object_or_none from .models import Terminal, Status, Session, Task from .backends import get_multi_command_storage @@ -45,7 +43,7 @@ class TerminalSerializer(serializers.ModelSerializer): return False -class SessionSerializer(serializers.ModelSerializer): +class SessionSerializer(BulkSerializerMixin, serializers.ModelSerializer): command_amount = serializers.SerializerMethodField() command_store = get_multi_command_storage() diff --git a/apps/terminal/templates/terminal/session_list.html b/apps/terminal/templates/terminal/session_list.html index c27b2f8a7..534dc4cd6 100644 --- a/apps/terminal/templates/terminal/session_list.html +++ b/apps/terminal/templates/terminal/session_list.html @@ -120,6 +120,7 @@