mirror of https://github.com/jumpserver/jumpserver
commit
957d3660ce
|
@ -22,7 +22,7 @@ from common.utils.common import timeit
|
||||||
from common.db.models import output_as_string
|
from common.db.models import output_as_string
|
||||||
from common.utils import get_logger
|
from common.utils import get_logger
|
||||||
from orgs.mixins.models import OrgModelMixin, OrgManager
|
from orgs.mixins.models import OrgModelMixin, OrgManager
|
||||||
from orgs.utils import get_current_org, tmp_to_org
|
from orgs.utils import get_current_org, tmp_to_org, tmp_to_root_org
|
||||||
from orgs.models import Organization
|
from orgs.models import Organization
|
||||||
|
|
||||||
|
|
||||||
|
@ -462,22 +462,42 @@ class NodeAssetsMixin(NodeAllAssetsMappingMixin):
|
||||||
class SomeNodesMixin:
|
class SomeNodesMixin:
|
||||||
key = ''
|
key = ''
|
||||||
default_key = '1'
|
default_key = '1'
|
||||||
default_value = 'Default'
|
|
||||||
empty_key = '-11'
|
empty_key = '-11'
|
||||||
empty_value = _("empty")
|
empty_value = _("empty")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def correct_default_node_if_need(cls):
|
||||||
|
with tmp_to_root_org():
|
||||||
|
wrong_default_org = cls.objects.filter(key='1', value='Default').first()
|
||||||
|
if not wrong_default_org:
|
||||||
|
return
|
||||||
|
|
||||||
|
if wrong_default_org.has_children_or_has_assets():
|
||||||
|
return
|
||||||
|
|
||||||
|
default_org = Organization.default()
|
||||||
|
right_default_org = cls.objects.filter(value=default_org.name).first()
|
||||||
|
if not right_default_org:
|
||||||
|
return
|
||||||
|
|
||||||
|
if right_default_org.date_create > wrong_default_org.date_create:
|
||||||
|
return
|
||||||
|
|
||||||
|
with atomic():
|
||||||
|
logger.warn(f'Correct default node: '
|
||||||
|
f'old={wrong_default_org.value}-{wrong_default_org.key} '
|
||||||
|
f'new={right_default_org.value}-{right_default_org.key}')
|
||||||
|
wrong_default_org.delete()
|
||||||
|
right_default_org.key = '1'
|
||||||
|
right_default_org.save()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def default_node(cls):
|
def default_node(cls):
|
||||||
|
cls.correct_default_node_if_need()
|
||||||
|
|
||||||
default_org = Organization.default()
|
default_org = Organization.default()
|
||||||
with tmp_to_org(default_org):
|
with tmp_to_org(default_org):
|
||||||
defaults = {'value': default_org.name}
|
defaults = {'value': default_org.name}
|
||||||
try:
|
|
||||||
obj, created = cls.objects.get_or_create(
|
|
||||||
defaults=defaults, key=cls.default_key,
|
|
||||||
)
|
|
||||||
except IntegrityError as e:
|
|
||||||
logger.error("Create default node failed: {}".format(e))
|
|
||||||
cls.modify_other_org_root_node_key()
|
|
||||||
obj, created = cls.objects.get_or_create(
|
obj, created = cls.objects.get_or_create(
|
||||||
defaults=defaults, key=cls.default_key,
|
defaults=defaults, key=cls.default_key,
|
||||||
)
|
)
|
||||||
|
@ -500,7 +520,7 @@ class SomeNodesMixin:
|
||||||
if not org_nodes_roots_keys:
|
if not org_nodes_roots_keys:
|
||||||
org_nodes_roots_keys = ['1']
|
org_nodes_roots_keys = ['1']
|
||||||
max_key = max([int(k) for k in org_nodes_roots_keys])
|
max_key = max([int(k) for k in org_nodes_roots_keys])
|
||||||
key = str(max_key + 1) if max_key != 0 else '2'
|
key = str(max_key + 1) if max_key > 0 else '2'
|
||||||
return key
|
return key
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
|
@ -23,6 +23,7 @@ class AdminUserSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
|
||||||
read_only_fields = ['date_created', 'date_updated', 'created_by', 'assets_amount']
|
read_only_fields = ['date_created', 'date_updated', 'created_by', 'assets_amount']
|
||||||
|
|
||||||
extra_kwargs = {
|
extra_kwargs = {
|
||||||
|
'username': {"required": True},
|
||||||
'password': {"write_only": True},
|
'password': {"write_only": True},
|
||||||
'private_key': {"write_only": True},
|
'private_key': {"write_only": True},
|
||||||
'public_key': {"write_only": True},
|
'public_key': {"write_only": True},
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
|
|
||||||
from django.contrib.auth import BACKEND_SESSION_KEY
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth import user_logged_in
|
from django.contrib.auth import user_logged_in
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
|
@ -25,17 +24,17 @@ def on_user_auth_login_success(sender, user, request, **kwargs):
|
||||||
|
|
||||||
@receiver(openid_user_login_success)
|
@receiver(openid_user_login_success)
|
||||||
def on_oidc_user_login_success(sender, request, user, create=False, **kwargs):
|
def on_oidc_user_login_success(sender, request, user, create=False, **kwargs):
|
||||||
request.session[BACKEND_SESSION_KEY] = 'OIDCAuthCodeBackend'
|
request.session['auth_backend'] = settings.AUTH_BACKEND_OIDC_CODE
|
||||||
post_auth_success.send(sender, user=user, request=request)
|
post_auth_success.send(sender, user=user, request=request)
|
||||||
|
|
||||||
|
|
||||||
@receiver(openid_user_login_failed)
|
@receiver(openid_user_login_failed)
|
||||||
def on_oidc_user_login_failed(sender, username, request, reason, **kwargs):
|
def on_oidc_user_login_failed(sender, username, request, reason, **kwargs):
|
||||||
request.session[BACKEND_SESSION_KEY] = 'OIDCAuthCodeBackend'
|
request.session['auth_backend'] = settings.AUTH_BACKEND_OIDC_CODE
|
||||||
post_auth_failed.send(sender, username=username, request=request, reason=reason)
|
post_auth_failed.send(sender, username=username, request=request, reason=reason)
|
||||||
|
|
||||||
|
|
||||||
@receiver(cas_user_authenticated)
|
@receiver(cas_user_authenticated)
|
||||||
def on_cas_user_login_success(sender, request, user, **kwargs):
|
def on_cas_user_login_success(sender, request, user, **kwargs):
|
||||||
request.session[BACKEND_SESSION_KEY] = 'CASBackend'
|
request.session['auth_backend'] = settings.AUTH_BACKEND_CAS
|
||||||
post_auth_success.send(sender, user=user, request=request)
|
post_auth_success.send(sender, user=user, request=request)
|
||||||
|
|
|
@ -109,9 +109,9 @@ class PermissionsMixin(UserPassesTestMixin):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
class UserCanUseCurrentOrg(permissions.BasePermission):
|
class UserCanAnyPermCurrentOrg(permissions.BasePermission):
|
||||||
def has_permission(self, request, view):
|
def has_permission(self, request, view):
|
||||||
return current_org.can_use_by(request.user)
|
return current_org.can_any_by(request.user)
|
||||||
|
|
||||||
|
|
||||||
class UserCanUpdatePassword(permissions.BasePermission):
|
class UserCanUpdatePassword(permissions.BasePermission):
|
||||||
|
|
|
@ -8,7 +8,7 @@ from rest_framework_bulk import BulkModelViewSet
|
||||||
from rest_framework.generics import RetrieveAPIView
|
from rest_framework.generics import RetrieveAPIView
|
||||||
from rest_framework.exceptions import PermissionDenied
|
from rest_framework.exceptions import PermissionDenied
|
||||||
|
|
||||||
from common.permissions import IsSuperUserOrAppUser, IsValidUser, UserCanUseCurrentOrg
|
from common.permissions import IsSuperUserOrAppUser, IsValidUser, UserCanAnyPermCurrentOrg
|
||||||
from common.drf.api import JMSBulkRelationModelViewSet
|
from common.drf.api import JMSBulkRelationModelViewSet
|
||||||
from .models import Organization, ROLE
|
from .models import Organization, ROLE
|
||||||
from .serializers import (
|
from .serializers import (
|
||||||
|
@ -18,9 +18,13 @@ from .serializers import (
|
||||||
CurrentOrgSerializer
|
CurrentOrgSerializer
|
||||||
)
|
)
|
||||||
from users.models import User, UserGroup
|
from users.models import User, UserGroup
|
||||||
from assets.models import Asset, Domain, AdminUser, SystemUser, Label
|
from assets.models import (
|
||||||
from perms.models import AssetPermission
|
Asset, Domain, AdminUser, SystemUser, Label, Node, Gateway,
|
||||||
from orgs.utils import current_org
|
CommandFilter, CommandFilterRule, GatheredUser
|
||||||
|
)
|
||||||
|
from applications.models import Application
|
||||||
|
from perms.models import AssetPermission, ApplicationPermission
|
||||||
|
from orgs.utils import current_org, tmp_to_root_org
|
||||||
from common.utils import get_logger
|
from common.utils import get_logger
|
||||||
from .filters import OrgMemberRelationFilterSet
|
from .filters import OrgMemberRelationFilterSet
|
||||||
from .models import OrganizationMember
|
from .models import OrganizationMember
|
||||||
|
@ -29,6 +33,15 @@ from .models import OrganizationMember
|
||||||
logger = get_logger(__file__)
|
logger = get_logger(__file__)
|
||||||
|
|
||||||
|
|
||||||
|
# 部分 org 相关的 model,需要清空这些数据之后才能删除该组织
|
||||||
|
org_related_models = [
|
||||||
|
User, UserGroup, Asset, Label, Domain, Gateway, Node, AdminUser, SystemUser, Label,
|
||||||
|
CommandFilter, CommandFilterRule, GatheredUser,
|
||||||
|
AssetPermission, ApplicationPermission,
|
||||||
|
Application,
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class OrgViewSet(BulkModelViewSet):
|
class OrgViewSet(BulkModelViewSet):
|
||||||
filterset_fields = ('name',)
|
filterset_fields = ('name',)
|
||||||
search_fields = ('name', 'comment')
|
search_fields = ('name', 'comment')
|
||||||
|
@ -44,24 +57,23 @@ class OrgViewSet(BulkModelViewSet):
|
||||||
}
|
}
|
||||||
return mapper.get(self.action, super().get_serializer_class())
|
return mapper.get(self.action, super().get_serializer_class())
|
||||||
|
|
||||||
|
@tmp_to_root_org()
|
||||||
def get_data_from_model(self, model):
|
def get_data_from_model(self, model):
|
||||||
if model == User:
|
if model == User:
|
||||||
data = model.objects.filter(orgs__id=self.org.id, m2m_org_members__role=ROLE.USER)
|
data = model.objects.filter(orgs__id=self.org.id, m2m_org_members__role=ROLE.USER)
|
||||||
|
elif model == Node:
|
||||||
|
# 跟节点不能手动删除,所以排除检查
|
||||||
|
data = model.objects.filter(org_id=self.org.id).exclude(parent_key='', key__regex=r'^[0-9]+$')
|
||||||
else:
|
else:
|
||||||
data = model.objects.filter(org_id=self.org.id)
|
data = model.objects.filter(org_id=self.org.id)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def destroy(self, request, *args, **kwargs):
|
def destroy(self, request, *args, **kwargs):
|
||||||
self.org = self.get_object()
|
self.org = self.get_object()
|
||||||
models = [
|
for model in org_related_models:
|
||||||
User, UserGroup,
|
|
||||||
Asset, Domain, AdminUser, SystemUser, Label,
|
|
||||||
AssetPermission,
|
|
||||||
]
|
|
||||||
for model in models:
|
|
||||||
data = self.get_data_from_model(model)
|
data = self.get_data_from_model(model)
|
||||||
if data:
|
if data:
|
||||||
msg = _('Organization contains undeleted resources')
|
msg = _(f'Have `{model._meta.verbose_name}` exists, Please delete')
|
||||||
return Response(data={'error': msg}, status=status.HTTP_403_FORBIDDEN)
|
return Response(data={'error': msg}, status=status.HTTP_403_FORBIDDEN)
|
||||||
else:
|
else:
|
||||||
if str(current_org) == str(self.org):
|
if str(current_org) == str(self.org):
|
||||||
|
@ -136,7 +148,7 @@ class OrgMemberUserRelationBulkViewSet(JMSBulkRelationModelViewSet):
|
||||||
|
|
||||||
class CurrentOrgDetailApi(RetrieveAPIView):
|
class CurrentOrgDetailApi(RetrieveAPIView):
|
||||||
serializer_class = CurrentOrgSerializer
|
serializer_class = CurrentOrgSerializer
|
||||||
permission_classes = (IsValidUser, UserCanUseCurrentOrg)
|
permission_classes = (IsValidUser, UserCanAnyPermCurrentOrg)
|
||||||
|
|
||||||
def get_object(self):
|
def get_object(self):
|
||||||
return current_org
|
return current_org
|
||||||
|
|
|
@ -51,7 +51,14 @@ class Organization(models.Model):
|
||||||
def get_instance_from_memory(cls, id_or_name):
|
def get_instance_from_memory(cls, id_or_name):
|
||||||
if not isinstance(cls.orgs_mapping, dict):
|
if not isinstance(cls.orgs_mapping, dict):
|
||||||
cls.orgs_mapping = cls.construct_orgs_mapping()
|
cls.orgs_mapping = cls.construct_orgs_mapping()
|
||||||
return cls.orgs_mapping.get(str(id_or_name))
|
|
||||||
|
org = cls.orgs_mapping.get(str(id_or_name))
|
||||||
|
if not org:
|
||||||
|
# 内存失效速度慢于读取速度(on_org_create_or_update)
|
||||||
|
cls.orgs_mapping = cls.construct_orgs_mapping()
|
||||||
|
|
||||||
|
org = cls.orgs_mapping.get(str(id_or_name))
|
||||||
|
return org
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def construct_orgs_mapping(cls):
|
def construct_orgs_mapping(cls):
|
||||||
|
@ -111,6 +118,8 @@ class Organization(models.Model):
|
||||||
def can_audit_by(self, user):
|
def can_audit_by(self, user):
|
||||||
if user.is_superuser or user.is_super_auditor:
|
if user.is_superuser or user.is_super_auditor:
|
||||||
return True
|
return True
|
||||||
|
if self.can_admin_by(user):
|
||||||
|
return True
|
||||||
if self.auditors.filter(id=user.id).exists():
|
if self.auditors.filter(id=user.id).exists():
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
@ -118,10 +127,17 @@ class Organization(models.Model):
|
||||||
def can_use_by(self, user):
|
def can_use_by(self, user):
|
||||||
if user.is_superuser or user.is_super_auditor:
|
if user.is_superuser or user.is_super_auditor:
|
||||||
return True
|
return True
|
||||||
|
if self.can_audit_by(user):
|
||||||
|
return True
|
||||||
if self.users.filter(id=user.id).exists():
|
if self.users.filter(id=user.id).exists():
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def can_any_by(self, user):
|
||||||
|
if user.is_superuser or user.is_super_auditor:
|
||||||
|
return True
|
||||||
|
return self.members.filter(id=user.id).exists()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_user_orgs_by_role(cls, user, role):
|
def get_user_orgs_by_role(cls, user, role):
|
||||||
if not isinstance(role, (tuple, list)):
|
if not isinstance(role, (tuple, list)):
|
||||||
|
|
|
@ -7,7 +7,8 @@ from functools import partial
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from django.utils.functional import LazyObject
|
from django.utils.functional import LazyObject
|
||||||
from django.db.models.signals import m2m_changed
|
from django.db.models.signals import m2m_changed
|
||||||
from django.db.models.signals import post_save, post_delete
|
from django.db.models.signals import post_save, post_delete, pre_delete
|
||||||
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
from orgs.utils import tmp_to_org
|
from orgs.utils import tmp_to_org
|
||||||
from orgs.models import Organization, OrganizationMember
|
from orgs.models import Organization, OrganizationMember
|
||||||
|
@ -18,6 +19,7 @@ from common.const.signals import PRE_REMOVE, POST_REMOVE
|
||||||
from common.signals import django_ready
|
from common.signals import django_ready
|
||||||
from common.utils import get_logger
|
from common.utils import get_logger
|
||||||
from common.utils.connection import RedisPubSub
|
from common.utils.connection import RedisPubSub
|
||||||
|
from common.exceptions import JMSException
|
||||||
|
|
||||||
|
|
||||||
logger = get_logger(__file__)
|
logger = get_logger(__file__)
|
||||||
|
@ -75,6 +77,15 @@ def on_org_delete(sender, **kwargs):
|
||||||
expire_orgs_mapping_for_memory()
|
expire_orgs_mapping_for_memory()
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(pre_delete, sender=Organization)
|
||||||
|
def on_org_delete(sender, instance, **kwargs):
|
||||||
|
# 删除该组织下所有 节点
|
||||||
|
with tmp_to_org(instance):
|
||||||
|
root_node = Node.org_root()
|
||||||
|
if root_node:
|
||||||
|
root_node.delete()
|
||||||
|
|
||||||
|
|
||||||
def _remove_users(model, users, org):
|
def _remove_users(model, users, org):
|
||||||
with tmp_to_org(org):
|
with tmp_to_org(org):
|
||||||
if not isinstance(users, (tuple, list, set)):
|
if not isinstance(users, (tuple, list, set)):
|
||||||
|
|
|
@ -98,12 +98,9 @@ class PublicSettingApi(generics.RetrieveAPIView):
|
||||||
def get_xpack_license_is_valid():
|
def get_xpack_license_is_valid():
|
||||||
if not settings.XPACK_ENABLED:
|
if not settings.XPACK_ENABLED:
|
||||||
return False
|
return False
|
||||||
try:
|
|
||||||
from xpack.plugins.license.models import License
|
from xpack.plugins.license.models import License
|
||||||
return License.has_valid_license()
|
return License.has_valid_license()
|
||||||
except Exception as e:
|
|
||||||
logger.error(e)
|
|
||||||
return False
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_login_title():
|
def get_login_title():
|
||||||
|
|
|
@ -10,7 +10,7 @@ from django_filters import utils
|
||||||
|
|
||||||
from terminal import const
|
from terminal import const
|
||||||
from common.const.http import GET
|
from common.const.http import GET
|
||||||
from common.permissions import IsSuperUser
|
from common.permissions import IsSuperUser, IsOrgAuditor
|
||||||
from terminal.filters import CommandStorageFilter, CommandFilter, CommandFilterForStorageTree
|
from terminal.filters import CommandStorageFilter, CommandFilter, CommandFilterForStorageTree
|
||||||
from ..models import CommandStorage, ReplayStorage
|
from ..models import CommandStorage, ReplayStorage
|
||||||
from ..serializers import CommandStorageSerializer, ReplayStorageSerializer
|
from ..serializers import CommandStorageSerializer, ReplayStorageSerializer
|
||||||
|
@ -42,7 +42,7 @@ class CommandStorageViewSet(BaseStorageViewSetMixin, viewsets.ModelViewSet):
|
||||||
permission_classes = (IsSuperUser,)
|
permission_classes = (IsSuperUser,)
|
||||||
filterset_class = CommandStorageFilter
|
filterset_class = CommandStorageFilter
|
||||||
|
|
||||||
@action(methods=[GET], detail=False, filterset_class=CommandFilterForStorageTree)
|
@action(methods=[GET], detail=False, permission_classes=(IsOrgAuditor, ), filterset_class=CommandFilterForStorageTree)
|
||||||
def tree(self, request: Request):
|
def tree(self, request: Request):
|
||||||
storage_qs = self.get_queryset().exclude(name='null')
|
storage_qs = self.get_queryset().exclude(name='null')
|
||||||
storages_with_count = []
|
storages_with_count = []
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
|
from django.conf import settings
|
||||||
from rest_framework import generics
|
from rest_framework import generics
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework_bulk import BulkModelViewSet
|
from rest_framework_bulk import BulkModelViewSet
|
||||||
|
@ -88,16 +88,13 @@ class UserViewSet(CommonApiMixin, UserQuerysetMixin, BulkModelViewSet):
|
||||||
|
|
||||||
def get_permissions(self):
|
def get_permissions(self):
|
||||||
if self.action in ["retrieve", "list"]:
|
if self.action in ["retrieve", "list"]:
|
||||||
self.permission_classes = (IsOrgAdminOrAppUser,)
|
|
||||||
if self.request.query_params.get('all'):
|
if self.request.query_params.get('all'):
|
||||||
self.permission_classes = (IsSuperUser,)
|
self.permission_classes = (IsSuperUser,)
|
||||||
return super().get_permissions()
|
|
||||||
|
|
||||||
def perform_destroy(self, instance):
|
|
||||||
if not current_org.is_root():
|
|
||||||
instance.remove()
|
|
||||||
else:
|
else:
|
||||||
return super().perform_destroy(instance)
|
self.permission_classes = (IsOrgAdminOrAppUser,)
|
||||||
|
elif self.action in ['destroy']:
|
||||||
|
self.permission_classes = (IsSuperUser,)
|
||||||
|
return super().get_permissions()
|
||||||
|
|
||||||
def perform_bulk_destroy(self, objects):
|
def perform_bulk_destroy(self, objects):
|
||||||
for obj in objects:
|
for obj in objects:
|
||||||
|
@ -164,6 +161,21 @@ class UserViewSet(CommonApiMixin, UserQuerysetMixin, BulkModelViewSet):
|
||||||
OrganizationMember.objects.bulk_create(relations, ignore_conflicts=True)
|
OrganizationMember.objects.bulk_create(relations, ignore_conflicts=True)
|
||||||
return Response(serializer.data, status=201)
|
return Response(serializer.data, status=201)
|
||||||
|
|
||||||
|
@action(methods=['post'], detail=True, permission_classes=(IsOrgAdmin,))
|
||||||
|
def remove(self, request, *args, **kwargs):
|
||||||
|
instance = self.get_object()
|
||||||
|
instance.remove()
|
||||||
|
return Response(status=204)
|
||||||
|
|
||||||
|
@action(methods=['post'], detail=False, permission_classes=(IsOrgAdmin,), url_path='remove')
|
||||||
|
def bulk_remove(self, request, *args, **kwargs):
|
||||||
|
qs = self.get_queryset()
|
||||||
|
filtered = self.filter_queryset(qs)
|
||||||
|
|
||||||
|
for instance in filtered:
|
||||||
|
instance.remove()
|
||||||
|
return Response(status=204)
|
||||||
|
|
||||||
|
|
||||||
class UserChangePasswordApi(UserQuerysetMixin, generics.RetrieveUpdateAPIView):
|
class UserChangePasswordApi(UserQuerysetMixin, generics.RetrieveUpdateAPIView):
|
||||||
permission_classes = (IsOrgAdmin,)
|
permission_classes = (IsOrgAdmin,)
|
||||||
|
|
|
@ -11,6 +11,8 @@ from .user import UserSerializer
|
||||||
class UserOrgSerializer(serializers.Serializer):
|
class UserOrgSerializer(serializers.Serializer):
|
||||||
id = serializers.CharField()
|
id = serializers.CharField()
|
||||||
name = serializers.CharField()
|
name = serializers.CharField()
|
||||||
|
is_default = serializers.BooleanField(read_only=True)
|
||||||
|
is_root = serializers.BooleanField(read_only=True)
|
||||||
|
|
||||||
|
|
||||||
class UserOrgLabelSerializer(serializers.Serializer):
|
class UserOrgLabelSerializer(serializers.Serializer):
|
||||||
|
|
|
@ -51,9 +51,6 @@ class UserOtpEnableInstallAppView(TemplateView):
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class UserOtpEnableBindView(AuthMixin, TemplateView, FormView):
|
class UserOtpEnableBindView(AuthMixin, TemplateView, FormView):
|
||||||
template_name = 'users/user_otp_enable_bind.html'
|
template_name = 'users/user_otp_enable_bind.html'
|
||||||
form_class = forms.UserCheckOtpCodeForm
|
form_class = forms.UserCheckOtpCodeForm
|
||||||
|
|
2
jms
2
jms
|
@ -28,7 +28,7 @@ try:
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
print("Not found __version__: {}".format(e))
|
print("Not found __version__: {}".format(e))
|
||||||
print("Python is: ")
|
print("Python is: ")
|
||||||
logging.info(subprocess.call('which python', shell=True))
|
logging.info(sys.executable)
|
||||||
__version__ = 'Unknown'
|
__version__ = 'Unknown'
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue