From 9bf5d6dd450685004f94b2f267fa90e1a0ba54fb Mon Sep 17 00:00:00 2001 From: ibuler Date: Fri, 20 Mar 2020 18:21:27 +0800 Subject: [PATCH 01/27] =?UTF-8?q?[Update]=20=E7=94=A8=E6=88=B7profile?= =?UTF-8?q?=E4=B8=AD=E6=B7=BB=E5=8A=A0orgs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/users/api/__init__.py | 1 + apps/users/api/mixins.py | 9 +++++ apps/users/api/profile.py | 68 +++++++++++++++++++++++++++++++++ apps/users/api/user.py | 69 ++-------------------------------- apps/users/models/user.py | 5 +++ apps/users/serializers/user.py | 9 ++++- 6 files changed, 95 insertions(+), 66 deletions(-) create mode 100644 apps/users/api/mixins.py create mode 100644 apps/users/api/profile.py diff --git a/apps/users/api/__init__.py b/apps/users/api/__init__.py index 965337c42..df750c107 100644 --- a/apps/users/api/__init__.py +++ b/apps/users/api/__init__.py @@ -3,4 +3,5 @@ from .user import * from .group import * +from .profile import * from .relation import * diff --git a/apps/users/api/mixins.py b/apps/users/api/mixins.py new file mode 100644 index 000000000..273ab9074 --- /dev/null +++ b/apps/users/api/mixins.py @@ -0,0 +1,9 @@ +# -*- coding: utf-8 -*- +# +from .. import utils + + +class UserQuerysetMixin: + def get_queryset(self): + queryset = utils.get_current_org_members() + return queryset diff --git a/apps/users/api/profile.py b/apps/users/api/profile.py new file mode 100644 index 000000000..70e028a85 --- /dev/null +++ b/apps/users/api/profile.py @@ -0,0 +1,68 @@ +# ~*~ coding: utf-8 ~*~ +import uuid + +from rest_framework import generics +from rest_framework.permissions import IsAuthenticated + +from common.permissions import ( + IsCurrentUserOrReadOnly +) +from .. import serializers +from ..models import User +from .mixins import UserQuerysetMixin + +__all__ = [ + 'UserResetPasswordApi', 'UserResetPKApi', + 'UserProfileApi', 'UserUpdatePKApi', +] + + +class UserResetPasswordApi(UserQuerysetMixin, generics.UpdateAPIView): + queryset = User.objects.all() + serializer_class = serializers.UserSerializer + permission_classes = (IsAuthenticated,) + + def perform_update(self, serializer): + # Note: we are not updating the user object here. + # We just do the reset-password stuff. + from ..utils import send_reset_password_mail + user = self.get_object() + user.password_raw = str(uuid.uuid4()) + user.save() + send_reset_password_mail(user) + + +class UserResetPKApi(UserQuerysetMixin, generics.UpdateAPIView): + serializer_class = serializers.UserSerializer + permission_classes = (IsAuthenticated,) + + def perform_update(self, serializer): + from ..utils import send_reset_ssh_key_mail + user = self.get_object() + user.public_key = None + user.save() + send_reset_ssh_key_mail(user) + + +# 废弃 +class UserUpdatePKApi(UserQuerysetMixin, generics.UpdateAPIView): + serializer_class = serializers.UserPKUpdateSerializer + permission_classes = (IsCurrentUserOrReadOnly,) + + def perform_update(self, serializer): + user = self.get_object() + user.public_key = serializer.validated_data['public_key'] + user.save() + + +class UserProfileApi(generics.RetrieveAPIView): + permission_classes = (IsAuthenticated,) + serializer_class = serializers.UserSerializer + + def get_object(self): + return self.request.user + + def retrieve(self, request, *args, **kwargs): + age = request.session.get_expiry_age() + request.session.set_expiry(age) + return super().retrieve(request, *args, **kwargs) diff --git a/apps/users/api/user.py b/apps/users/api/user.py index 98dcbd91c..fac0fabca 100644 --- a/apps/users/api/user.py +++ b/apps/users/api/user.py @@ -1,23 +1,20 @@ # ~*~ coding: utf-8 ~*~ -import uuid - from django.core.cache import cache -from django.contrib.auth import logout from django.utils.translation import ugettext as _ from rest_framework import generics from rest_framework.response import Response -from rest_framework.permissions import IsAuthenticated from rest_framework_bulk import BulkModelViewSet from common.permissions import ( - IsOrgAdmin, IsCurrentUserOrReadOnly, IsOrgAdminOrAppUser, + IsOrgAdmin, IsOrgAdminOrAppUser, CanUpdateDeleteUser, IsSuperUser ) from common.mixins import CommonApiMixin from common.utils import get_logger from orgs.utils import current_org -from .. import serializers, utils +from .. import serializers +from .mixins import UserQuerysetMixin from ..models import User from ..signals import post_user_create @@ -25,17 +22,10 @@ from ..signals import post_user_create logger = get_logger(__name__) __all__ = [ 'UserViewSet', 'UserChangePasswordApi', - 'UserResetPasswordApi', 'UserResetPKApi', 'UserUpdatePKApi', - 'UserUnblockPKApi', 'UserProfileApi', 'UserResetOTPApi', + 'UserUnblockPKApi', 'UserResetOTPApi', ] -class UserQuerysetMixin: - def get_queryset(self): - queryset = utils.get_current_org_members() - return queryset - - class UserViewSet(CommonApiMixin, UserQuerysetMixin, BulkModelViewSet): filter_fields = ('username', 'email', 'name', 'id') search_fields = filter_fields @@ -101,44 +91,6 @@ class UserChangePasswordApi(UserQuerysetMixin, generics.RetrieveUpdateAPIView): user.save() -class UserResetPasswordApi(UserQuerysetMixin, generics.UpdateAPIView): - queryset = User.objects.all() - serializer_class = serializers.UserSerializer - permission_classes = (IsAuthenticated,) - - def perform_update(self, serializer): - # Note: we are not updating the user object here. - # We just do the reset-password stuff. - from ..utils import send_reset_password_mail - user = self.get_object() - user.password_raw = str(uuid.uuid4()) - user.save() - send_reset_password_mail(user) - - -class UserResetPKApi(UserQuerysetMixin, generics.UpdateAPIView): - serializer_class = serializers.UserSerializer - permission_classes = (IsAuthenticated,) - - def perform_update(self, serializer): - from ..utils import send_reset_ssh_key_mail - user = self.get_object() - user.public_key = None - user.save() - send_reset_ssh_key_mail(user) - - -# 废弃 -class UserUpdatePKApi(UserQuerysetMixin, generics.UpdateAPIView): - serializer_class = serializers.UserPKUpdateSerializer - permission_classes = (IsCurrentUserOrReadOnly,) - - def perform_update(self, serializer): - user = self.get_object() - user.public_key = serializer.validated_data['public_key'] - user.save() - - class UserUnblockPKApi(UserQuerysetMixin, generics.UpdateAPIView): permission_classes = (IsOrgAdmin,) serializer_class = serializers.UserSerializer @@ -154,19 +106,6 @@ class UserUnblockPKApi(UserQuerysetMixin, generics.UpdateAPIView): cache.delete(key_block) -class UserProfileApi(generics.RetrieveAPIView): - permission_classes = (IsAuthenticated,) - serializer_class = serializers.UserSerializer - - def get_object(self): - return self.request.user - - def retrieve(self, request, *args, **kwargs): - age = request.session.get_expiry_age() - request.session.set_expiry(age) - return super().retrieve(request, *args, **kwargs) - - class UserResetOTPApi(UserQuerysetMixin, generics.RetrieveAPIView): permission_classes = (IsOrgAdmin,) serializer_class = serializers.ResetOTPSerializer diff --git a/apps/users/models/user.py b/apps/users/models/user.py index b696795a8..7e81340fd 100644 --- a/apps/users/models/user.py +++ b/apps/users/models/user.py @@ -563,6 +563,11 @@ class User(AuthMixin, TokenMixin, RoleMixin, MFAMixin, AbstractUser): user_default = settings.STATIC_URL + "img/avatar/user.png" return user_default + def admin_orgs(self): + from orgs.models import Organization + orgs = Organization.get_user_admin_or_audit_orgs(self) + return orgs + def avatar_url(self): admin_default = settings.STATIC_URL + "img/avatar/admin.png" user_default = settings.STATIC_URL + "img/avatar/user.png" diff --git a/apps/users/serializers/user.py b/apps/users/serializers/user.py index da9b725ec..f2b3cc0bc 100644 --- a/apps/users/serializers/user.py +++ b/apps/users/serializers/user.py @@ -17,7 +17,13 @@ __all__ = [ ] +class UserOrgSerializer(serializers.Serializer): + id = serializers.CharField() + name = serializers.CharField() + + class UserSerializer(BulkSerializerMixin, serializers.ModelSerializer): + admin_orgs = UserOrgSerializer(many=True, read_only=True) class Meta: model = User @@ -27,7 +33,8 @@ class UserSerializer(BulkSerializerMixin, serializers.ModelSerializer): 'groups', 'role', 'wechat', 'phone', 'mfa_level', 'comment', 'source', 'is_valid', 'is_expired', 'is_active', 'created_by', 'is_first_login', - 'date_password_last_updated', 'date_expired', 'avatar_url', + 'date_password_last_updated', 'date_expired', + 'avatar_url', 'admin_orgs', ] extra_kwargs = { 'password': {'write_only': True, 'required': False, 'allow_null': True, 'allow_blank': True}, From dffd05cd20b31cece248b326e838cc363b82f9b9 Mon Sep 17 00:00:00 2001 From: ibuler Date: Mon, 23 Mar 2020 10:52:26 +0800 Subject: [PATCH 02/27] =?UTF-8?q?[Update]=20=E4=BF=AE=E6=94=B9=E7=BB=84?= =?UTF-8?q?=E7=BB=87=E8=8E=B7=E5=8F=96=E4=BC=98=E5=85=88=E7=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/orgs/utils.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/orgs/utils.py b/apps/orgs/utils.py index c69af25b8..d5ea4ca30 100644 --- a/apps/orgs/utils.py +++ b/apps/orgs/utils.py @@ -11,10 +11,9 @@ from .models import Organization def get_org_from_request(request): - oid = request.session.get("oid") + oid = request.META.get("HTTP_X_JMS_ORG") if not oid: - oid = request.META.get("HTTP_X_JMS_ORG") - + oid = request.session.get("oid") request_params_oid = request.GET.get("oid") if request_params_oid: oid = request.GET.get("oid") From e9103ee608b2a0993f93e3bfd6450205965307ce Mon Sep 17 00:00:00 2001 From: Bai Date: Thu, 2 Apr 2020 15:14:30 +0800 Subject: [PATCH 03/27] =?UTF-8?q?[Update]=20=E5=AF=B9=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89MetaDict=E5=AD=97=E6=AE=B5=E5=80=BC=E8=BF=9B=E8=A1=8Cs?= =?UTF-8?q?trip?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/common/fields/serializer.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/apps/common/fields/serializer.py b/apps/common/fields/serializer.py index a05b49376..e7a6e7d9c 100644 --- a/apps/common/fields/serializer.py +++ b/apps/common/fields/serializer.py @@ -101,6 +101,15 @@ class CustomMetaDictField(serializers.DictField): filter_value = {k: v for k, v in value.items() if k in fields_names} return filter_value + @staticmethod + def strip_value(value): + new_value = {} + for k, v in value.items(): + if isinstance(v, str): + v = v.strip() + new_value[k] = v + return new_value + def get_value(self, dictionary): """ 反序列化时调用 @@ -108,4 +117,5 @@ class CustomMetaDictField(serializers.DictField): value = super().get_value(dictionary) value = self.convert_value_key(dictionary, value) value = self.filter_value_key(dictionary, value) + value = self.strip_value(value) return value From e9fc56c0563a2edabcaab2bb694fbb949ce725e3 Mon Sep 17 00:00:00 2001 From: Bai Date: Thu, 2 Apr 2020 16:02:51 +0800 Subject: [PATCH 04/27] =?UTF-8?q?[Update]=20=E4=BF=AE=E6=94=B9=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E6=97=A5=E6=9C=9F=E6=98=BE=E7=A4=BA=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/static/js/jumpserver.js | 3 ++- apps/templates/_foot_js.html | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/static/js/jumpserver.js b/apps/static/js/jumpserver.js index 0adae3e10..9081d3a94 100644 --- a/apps/static/js/jumpserver.js +++ b/apps/static/js/jumpserver.js @@ -1256,7 +1256,8 @@ function toSafeDateISOStr(s) { function toSafeLocalDateStr(d) { var date = safeDate(d); - var date_s = date.toLocaleString(getUserLang(), {hour12: false}); + // var date_s = date.toLocaleString(getUserLang(), {hour12: false}); + var date_s = date.toLocaleString(getUserLang(), {hourCycle: "h23"}); return date_s.split("/").join('-') } diff --git a/apps/templates/_foot_js.html b/apps/templates/_foot_js.html index b140e7862..ff158b54b 100644 --- a/apps/templates/_foot_js.html +++ b/apps/templates/_foot_js.html @@ -7,7 +7,7 @@ - +