perf: 去掉 v2 的api

pull/5541/head
ibuler 2021-01-20 18:33:38 +08:00 committed by Jiangjie.Bai
parent d363118911
commit dd5b2b9101
20 changed files with 285 additions and 420 deletions

View File

@ -4,8 +4,6 @@ from __future__ import unicode_literals
from django.urls import path, include, re_path from django.urls import path, include, re_path
from django.conf import settings from django.conf import settings
from django.conf.urls.static import static from django.conf.urls.static import static
from django.conf.urls.i18n import i18n_patterns
from django.http import HttpResponse
from django.views.i18n import JavaScriptCatalog from django.views.i18n import JavaScriptCatalog
from . import views, api from . import views, api
@ -27,11 +25,6 @@ api_v1 = [
path('prometheus/metrics/', api.PrometheusMetricsApi.as_view()) path('prometheus/metrics/', api.PrometheusMetricsApi.as_view())
] ]
api_v2 = [
path('terminal/', include('terminal.urls.api_urls_v2', namespace='api-terminal-v2')),
path('users/', include('users.urls.api_urls_v2', namespace='api-users-v2')),
]
app_view_patterns = [ app_view_patterns = [
path('auth/', include('authentication.urls.view_urls'), name='auth'), path('auth/', include('authentication.urls.view_urls'), name='auth'),
path('ops/', include('ops.urls.view_urls'), name='ops'), path('ops/', include('ops.urls.view_urls'), name='ops'),
@ -53,7 +46,6 @@ apps = [
urlpatterns = [ urlpatterns = [
path('', views.IndexView.as_view(), name='index'), path('', views.IndexView.as_view(), name='index'),
path('api/v1/', include(api_v1)), path('api/v1/', include(api_v1)),
path('api/v2/', include(api_v2)),
re_path('api/(?P<app>\w+)/(?P<version>v\d)/.*', views.redirect_format_api), re_path('api/(?P<app>\w+)/(?P<version>v\d)/.*', views.redirect_format_api),
path('api/health/', views.HealthCheckView.as_view(), name="health"), path('api/health/', views.HealthCheckView.as_view(), name="health"),
# External apps url # External apps url
@ -77,11 +69,6 @@ urlpatterns += [
views.get_swagger_view().without_ui(cache_timeout=1), name='schema-json'), views.get_swagger_view().without_ui(cache_timeout=1), name='schema-json'),
re_path('api/docs/?', views.get_swagger_view().with_ui('swagger', cache_timeout=1), name="docs"), re_path('api/docs/?', views.get_swagger_view().with_ui('swagger', cache_timeout=1), name="docs"),
re_path('api/redoc/?', views.get_swagger_view().with_ui('redoc', cache_timeout=1), name='redoc'), re_path('api/redoc/?', views.get_swagger_view().with_ui('redoc', cache_timeout=1), name='redoc'),
re_path('^api/v2/swagger(?P<format>\.json|\.yaml)$',
views.get_swagger_view().without_ui(cache_timeout=1), name='schema-json'),
path('api/docs/v2/', views.get_swagger_view("v2").with_ui('swagger', cache_timeout=1), name="docs"),
path('api/redoc/v2/', views.get_swagger_view("v2").with_ui('redoc', cache_timeout=1), name='redoc'),
] ]

View File

@ -60,20 +60,12 @@ api_info = openapi.Info(
def get_swagger_view(version='v1'): def get_swagger_view(version='v1'):
from ..urls import api_v1, api_v2 from ..urls import api_v1
from django.urls import path, include from django.urls import path, include
api_v1_patterns = [ api_v1_patterns = [
path('api/v1/', include(api_v1)) path('api/v1/', include(api_v1))
] ]
patterns = api_v1_patterns
api_v2_patterns = [
path('api/v2/', include(api_v2))
]
if version == "v2":
patterns = api_v2_patterns
else:
patterns = api_v1_patterns
schema_view = get_schema_view( schema_view = get_schema_view(
api_info, api_info,
patterns=patterns, patterns=patterns,

View File

@ -5,18 +5,22 @@ import uuid
from django.core.cache import cache from django.core.cache import cache
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from rest_framework import viewsets from rest_framework import viewsets, generics
from rest_framework.views import APIView, Response from rest_framework.views import APIView, Response
from rest_framework import status
from django.conf import settings
from common.drf.api import JMSBulkModelViewSet from common.drf.api import JMSBulkModelViewSet
from common.utils import get_object_or_none from common.utils import get_object_or_none
from common.permissions import IsAppUser, IsOrgAdminOrAppUser, IsSuperUser from common.permissions import IsAppUser, IsOrgAdminOrAppUser, IsSuperUser, WithBootstrapToken
from ..models import Terminal, Status, Session from ..models import Terminal, Status, Session
from .. import serializers from .. import serializers
from .. import exceptions from .. import exceptions
__all__ = [ __all__ = [
'TerminalViewSet', 'StatusViewSet', 'TerminalConfig', 'TerminalViewSet', 'StatusViewSet', 'TerminalConfig',
'TerminalRegistrationApi',
] ]
logger = logging.getLogger(__file__) logger = logging.getLogger(__file__)
@ -112,4 +116,16 @@ class TerminalConfig(APIView):
def get(self, request): def get(self, request):
config = request.user.terminal.config config = request.user.terminal.config
return Response(config, status=200) return Response(config, status=200)
class TerminalRegistrationApi(generics.CreateAPIView):
serializer_class = serializers.TerminalRegistrationSerializer
permission_classes = [WithBootstrapToken]
http_method_names = ['post']
def create(self, request, *args, **kwargs):
if not settings.SECURITY_SERVICE_ACCOUNT_REGISTRATION:
data = {"error": "service account registration disabled"}
return Response(data=data, status=status.HTTP_400_BAD_REQUEST)
return super().create(request, *args, **kwargs)

View File

@ -1,3 +0,0 @@
# -*- coding: utf-8 -*-
#
from .terminal import *

View File

@ -1,44 +0,0 @@
# -*- coding: utf-8 -*-
#
from rest_framework import viewsets, generics
from rest_framework import status
from rest_framework.response import Response
from django.conf import settings
from common.permissions import IsSuperUser, WithBootstrapToken
from ..models import Terminal
from .. import serializers_v2 as serializers
__all__ = ['TerminalViewSet', 'TerminalRegistrationApi']
class TerminalViewSet(viewsets.ModelViewSet):
queryset = Terminal.objects.filter(is_deleted=False)
serializer_class = serializers.TerminalSerializer
permission_classes = [IsSuperUser]
http_method_names = [
'get', 'put', 'patch', 'delete', 'head', 'options', 'trace'
]
class TerminalRegistrationApi(generics.CreateAPIView):
serializer_class = serializers.TerminalRegistrationSerializer
permission_classes = [WithBootstrapToken]
http_method_names = ['post']
def create(self, request, *args, **kwargs):
data = {k: v for k, v in request.data.items()}
serializer = serializers.TerminalSerializer(
data=data, context={'request': request}
)
if not settings.SECURITY_SERVICE_ACCOUNT_REGISTRATION:
data = {"error": "service account registration disabled"}
return Response(data=data, status=status.HTTP_400_BAD_REQUEST)
serializer.is_valid(raise_exception=True)
terminal = serializer.save()
sa_serializer = serializer.sa_serializer_class(instance=terminal.user)
data['service_account'] = sa_serializer.data
return Response(data, status=status.HTTP_201_CREATED)

View File

@ -3,6 +3,9 @@ from django.utils.translation import ugettext_lazy as _
from common.drf.serializers import BulkModelSerializer, AdaptedBulkListSerializer from common.drf.serializers import BulkModelSerializer, AdaptedBulkListSerializer
from common.utils import is_uuid from common.utils import is_uuid
from users.serializers import ServiceAccountSerializer
from common.utils import get_request_ip
from ..models import ( from ..models import (
Terminal, Status, Session, Task, CommandStorage, ReplayStorage Terminal, Status, Session, Task, CommandStorage, ReplayStorage
) )
@ -63,9 +66,42 @@ class StatusSerializer(serializers.ModelSerializer):
class TaskSerializer(BulkModelSerializer): class TaskSerializer(BulkModelSerializer):
class Meta: class Meta:
fields = '__all__' fields = '__all__'
model = Task model = Task
list_serializer_class = AdaptedBulkListSerializer list_serializer_class = AdaptedBulkListSerializer
ref_name = 'TerminalTaskSerializer' ref_name = 'TerminalTaskSerializer'
class TerminalRegistrationSerializer(serializers.ModelSerializer):
service_account = ServiceAccountSerializer(read_only=True)
class Meta:
model = Terminal
fields = ['name', 'type', 'comment', 'service_account', 'remote_addr']
extra_fields = {
'remote_addr': {'readonly': True}
}
def is_valid(self, raise_exception=False):
valid = super().is_valid(raise_exception=raise_exception)
if not valid:
return valid
data = {'name': self.validated_data.get('name')}
kwargs = {'data': data}
if self.instance and self.instance.user:
kwargs['instance'] = self.instance.user
self.service_account = ServiceAccountSerializer(**kwargs)
valid = self.service_account.is_valid(raise_exception=True)
return valid
def save(self, **kwargs):
instance = super().save(**kwargs)
request = self.context.get('request')
instance.is_accepted = True
if request:
instance.remote_addr = get_request_ip(request)
sa = self.service_account.save()
instance.user = sa
instance.save()
return instance

View File

@ -1,4 +0,0 @@
# -*- coding: utf-8 -*-
#
from .terminal import *

View File

@ -1,60 +0,0 @@
# -*- coding: utf-8 -*-
#
from django.conf import settings
from rest_framework import serializers
from common.utils import get_request_ip
from users.serializers_v2 import ServiceAccountSerializer
from ..models import Terminal
__all__ = ['TerminalSerializer', 'TerminalRegistrationSerializer']
class TerminalSerializer(serializers.ModelSerializer):
sa_serializer_class = ServiceAccountSerializer
sa_serializer = None
class Meta:
model = Terminal
fields = [
'id', 'name', 'type', 'remote_addr', 'command_storage',
'replay_storage', 'user', 'is_accepted', 'is_deleted',
'date_created', 'comment'
]
read_only_fields = ['remote_addr', 'user', 'date_created']
def is_valid(self, raise_exception=False):
valid = super().is_valid(raise_exception=raise_exception)
if not valid:
return valid
data = {'name': self.validated_data.get('name')}
kwargs = {'data': data}
if self.instance and self.instance.user:
kwargs['instance'] = self.instance.user
self.sa_serializer = ServiceAccountSerializer(**kwargs)
valid = self.sa_serializer.is_valid(raise_exception=True)
return valid
def save(self, **kwargs):
instance = super().save(**kwargs)
sa = self.sa_serializer.save()
instance.user = sa
instance.save()
return instance
def create(self, validated_data):
request = self.context.get('request')
instance = super().create(validated_data)
instance.is_accepted = True
if request:
instance.remote_addr = get_request_ip(request)
instance.save()
return instance
class TerminalRegistrationSerializer(serializers.Serializer):
name = serializers.CharField(max_length=128)
comment = serializers.CharField(max_length=128)
type = serializers.CharField(max_length=64)
service_account = ServiceAccountSerializer(read_only=True)

View File

@ -22,6 +22,7 @@ router.register(r'replay-storages', api.ReplayStorageViewSet, 'replay-storage')
router.register(r'command-storages', api.CommandStorageViewSet, 'command-storage') router.register(r'command-storages', api.CommandStorageViewSet, 'command-storage')
urlpatterns = [ urlpatterns = [
path('terminal-registrations/', api.TerminalRegistrationApi.as_view(), name='terminal-registration'),
path('sessions/join/validate/', api.SessionJoinValidateAPI.as_view(), name='join-session-validate'), path('sessions/join/validate/', api.SessionJoinValidateAPI.as_view(), name='join-session-validate'),
path('sessions/<uuid:pk>/replay/', path('sessions/<uuid:pk>/replay/',
api.SessionReplayViewSet.as_view({'get': 'retrieve', 'post': 'create'}), api.SessionReplayViewSet.as_view({'get': 'retrieve', 'post': 'create'}),

View File

@ -1,26 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
from django.urls import path, re_path
from rest_framework_bulk.routes import BulkRouter
from common import api as capi
from .. import api_v2 as api
app_name = 'terminal'
router = BulkRouter()
router.register(r'terminals', api.TerminalViewSet, 'terminal')
urlpatterns = [
path('terminal-registrations/', api.TerminalRegistrationApi.as_view(),
name='terminal-registration')
]
old_version_urlpatterns = [
re_path('(?P<resource>terminal)/.*', capi.redirect_plural_name_api)
]
urlpatterns += router.urls

View File

@ -4,4 +4,5 @@
from .user import * from .user import *
from .group import * from .group import *
from .profile import * from .profile import *
from .service_account import *
from .relation import * from .relation import *

View File

@ -3,7 +3,7 @@
from rest_framework import viewsets from rest_framework import viewsets
from common.permissions import WithBootstrapToken from common.permissions import WithBootstrapToken
from .. import serializers_v2 as serializers from .. import serializers
class ServiceAccountRegistrationViewSet(viewsets.ModelViewSet): class ServiceAccountRegistrationViewSet(viewsets.ModelViewSet):

View File

@ -1,4 +0,0 @@
# -*- coding: utf-8 -*-
#
from .user import *

View File

@ -1,5 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
from .user import * from .user import *
from .profile import *
from .group import * from .group import *
from .realtion import * from .realtion import *

View File

@ -0,0 +1,177 @@
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers
from common.utils import validate_ssh_public_key
from ..models import User
from .user import UserSerializer
class UserOrgSerializer(serializers.Serializer):
id = serializers.CharField()
name = serializers.CharField()
class UserOrgLabelSerializer(serializers.Serializer):
value = serializers.CharField(source='id')
label = serializers.CharField(source='name')
class UserUpdatePasswordSerializer(serializers.ModelSerializer):
old_password = serializers.CharField(required=True, max_length=128, write_only=True)
new_password = serializers.CharField(required=True, max_length=128, write_only=True)
new_password_again = serializers.CharField(required=True, max_length=128, write_only=True)
class Meta:
model = User
fields = ['old_password', 'new_password', 'new_password_again']
def validate_old_password(self, value):
if not self.instance.check_password(value):
msg = _('The old password is incorrect')
raise serializers.ValidationError(msg)
return value
@staticmethod
def validate_new_password(value):
from ..utils import check_password_rules
if not check_password_rules(value):
msg = _('Password does not match security rules')
raise serializers.ValidationError(msg)
return value
def validate_new_password_again(self, value):
if value != self.initial_data.get('new_password', ''):
msg = _('The newly set password is inconsistent')
raise serializers.ValidationError(msg)
return value
def update(self, instance, validated_data):
new_password = self.validated_data.get('new_password')
instance.reset_password(new_password)
return instance
class UserUpdatePublicKeySerializer(serializers.ModelSerializer):
public_key_comment = serializers.CharField(
source='get_public_key_comment', required=False, read_only=True, max_length=128
)
public_key_hash_md5 = serializers.CharField(
source='get_public_key_hash_md5', required=False, read_only=True, max_length=128
)
class Meta:
model = User
fields = ['public_key_comment', 'public_key_hash_md5', 'public_key']
extra_kwargs = {
'public_key': {'required': True, 'write_only': True, 'max_length': 2048}
}
@staticmethod
def validate_public_key(value):
if not validate_ssh_public_key(value):
raise serializers.ValidationError(_('Not a valid ssh public key'))
return value
def update(self, instance, validated_data):
new_public_key = self.validated_data.get('public_key')
instance.set_public_key(new_public_key)
return instance
class UserRoleSerializer(serializers.Serializer):
name = serializers.CharField(max_length=24)
display = serializers.CharField(max_length=64)
class UserProfileSerializer(UserSerializer):
admin_or_audit_orgs = UserOrgSerializer(many=True, read_only=True)
user_all_orgs = UserOrgLabelSerializer(many=True, read_only=True)
current_org_roles = serializers.ListField(read_only=True)
public_key_comment = serializers.CharField(
source='get_public_key_comment', required=False, read_only=True, max_length=128
)
public_key_hash_md5 = serializers.CharField(
source='get_public_key_hash_md5', required=False, read_only=True, max_length=128
)
MFA_LEVEL_CHOICES = (
(0, _('Disable')),
(1, _('Enable')),
)
mfa_level = serializers.ChoiceField(choices=MFA_LEVEL_CHOICES, label=_('MFA'), required=False)
guide_url = serializers.SerializerMethodField()
class Meta(UserSerializer.Meta):
fields = UserSerializer.Meta.fields + [
'public_key_comment', 'public_key_hash_md5', 'admin_or_audit_orgs', 'current_org_roles',
'guide_url', 'user_all_orgs'
]
read_only_fields = [
'date_joined', 'last_login', 'created_by', 'source'
]
extra_kwargs = dict(UserSerializer.Meta.extra_kwargs)
extra_kwargs.update({
'name': {'read_only': True, 'max_length': 128},
'username': {'read_only': True, 'max_length': 128},
'email': {'read_only': True},
'is_first_login': {'label': _('Is first login'), 'read_only': False},
'source': {'read_only': True},
'is_valid': {'read_only': True},
'is_active': {'read_only': True},
'groups': {'read_only': True},
'roles': {'read_only': True},
'password_strategy': {'read_only': True},
'date_expired': {'read_only': True},
'date_joined': {'read_only': True},
'last_login': {'read_only': True},
'role': {'read_only': True},
})
if 'password' in fields:
fields.remove('password')
extra_kwargs.pop('password', None)
@staticmethod
def get_guide_url(obj):
return settings.USER_GUIDE_URL
def validate_mfa_level(self, mfa_level):
if self.instance and self.instance.mfa_force_enabled:
return 2
return mfa_level
def validate_public_key(self, public_key):
if self.instance and self.instance.can_update_ssh_key():
if not validate_ssh_public_key(public_key):
raise serializers.ValidationError(_('Not a valid ssh public key'))
return public_key
return None
class UserPKUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'public_key']
@staticmethod
def validate_public_key(value):
if not validate_ssh_public_key(value):
raise serializers.ValidationError(_('Not a valid ssh public key'))
return value
class ChangeUserPasswordSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['password']
class ResetOTPSerializer(serializers.Serializer):
msg = serializers.CharField(read_only=True)
def create(self, validated_data):
pass
def update(self, instance, validated_data):
pass

View File

@ -1,11 +1,9 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
from django.core.cache import cache from django.core.cache import cache
from django.conf import settings
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers from rest_framework import serializers
from common.utils import validate_ssh_public_key
from common.mixins import CommonBulkSerializerMixin from common.mixins import CommonBulkSerializerMixin
from common.permissions import CanUpdateDeleteUser from common.permissions import CanUpdateDeleteUser
from orgs.models import ROLE as ORG_ROLE from orgs.models import ROLE as ORG_ROLE
@ -13,24 +11,11 @@ from ..models import User
__all__ = [ __all__ = [
'UserSerializer', 'UserPKUpdateSerializer', 'UserSerializer', 'UserRetrieveSerializer', 'MiniUserSerializer',
'ChangeUserPasswordSerializer', 'ResetOTPSerializer', 'InviteSerializer', 'ServiceAccountSerializer',
'UserProfileSerializer', 'UserOrgSerializer',
'UserUpdatePasswordSerializer', 'UserUpdatePublicKeySerializer',
'UserRetrieveSerializer', 'MiniUserSerializer', 'InviteSerializer'
] ]
class UserOrgSerializer(serializers.Serializer):
id = serializers.CharField()
name = serializers.CharField()
class UserOrgLabelSerializer(serializers.Serializer):
value = serializers.CharField(source='id')
label = serializers.CharField(source='name')
class UserSerializer(CommonBulkSerializerMixin, serializers.ModelSerializer): class UserSerializer(CommonBulkSerializerMixin, serializers.ModelSerializer):
EMAIL_SET_PASSWORD = _('Reset link will be generated and sent to the user') EMAIL_SET_PASSWORD = _('Reset link will be generated and sent to the user')
CUSTOM_PASSWORD = _('Set password') CUSTOM_PASSWORD = _('Set password')
@ -181,166 +166,6 @@ class UserRetrieveSerializer(UserSerializer):
fields = UserSerializer.Meta.fields + ['login_confirm_settings'] fields = UserSerializer.Meta.fields + ['login_confirm_settings']
class UserPKUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'public_key']
@staticmethod
def validate_public_key(value):
if not validate_ssh_public_key(value):
raise serializers.ValidationError(_('Not a valid ssh public key'))
return value
class ChangeUserPasswordSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['password']
class ResetOTPSerializer(serializers.Serializer):
msg = serializers.CharField(read_only=True)
def create(self, validated_data):
pass
def update(self, instance, validated_data):
pass
class UserRoleSerializer(serializers.Serializer):
name = serializers.CharField(max_length=24)
display = serializers.CharField(max_length=64)
class UserProfileSerializer(UserSerializer):
admin_or_audit_orgs = UserOrgSerializer(many=True, read_only=True)
user_all_orgs = UserOrgLabelSerializer(many=True, read_only=True)
current_org_roles = serializers.ListField(read_only=True)
public_key_comment = serializers.CharField(
source='get_public_key_comment', required=False, read_only=True, max_length=128
)
public_key_hash_md5 = serializers.CharField(
source='get_public_key_hash_md5', required=False, read_only=True, max_length=128
)
MFA_LEVEL_CHOICES = (
(0, _('Disable')),
(1, _('Enable')),
)
mfa_level = serializers.ChoiceField(choices=MFA_LEVEL_CHOICES, label=_('MFA'), required=False)
guide_url = serializers.SerializerMethodField()
class Meta(UserSerializer.Meta):
fields = UserSerializer.Meta.fields + [
'public_key_comment', 'public_key_hash_md5', 'admin_or_audit_orgs', 'current_org_roles',
'guide_url', 'user_all_orgs'
]
read_only_fields = [
'date_joined', 'last_login', 'created_by', 'source'
]
extra_kwargs = dict(UserSerializer.Meta.extra_kwargs)
extra_kwargs.update({
'name': {'read_only': True, 'max_length': 128},
'username': {'read_only': True, 'max_length': 128},
'email': {'read_only': True},
'is_first_login': {'label': _('Is first login'), 'read_only': False},
'source': {'read_only': True},
'is_valid': {'read_only': True},
'is_active': {'read_only': True},
'groups': {'read_only': True},
'roles': {'read_only': True},
'password_strategy': {'read_only': True},
'date_expired': {'read_only': True},
'date_joined': {'read_only': True},
'last_login': {'read_only': True},
'role': {'read_only': True},
})
if 'password' in fields:
fields.remove('password')
extra_kwargs.pop('password', None)
@staticmethod
def get_guide_url(obj):
return settings.USER_GUIDE_URL
def validate_mfa_level(self, mfa_level):
if self.instance and self.instance.mfa_force_enabled:
return 2
return mfa_level
def validate_public_key(self, public_key):
if self.instance and self.instance.can_update_ssh_key():
if not validate_ssh_public_key(public_key):
raise serializers.ValidationError(_('Not a valid ssh public key'))
return public_key
return None
class UserUpdatePasswordSerializer(serializers.ModelSerializer):
old_password = serializers.CharField(required=True, max_length=128, write_only=True)
new_password = serializers.CharField(required=True, max_length=128, write_only=True)
new_password_again = serializers.CharField(required=True, max_length=128, write_only=True)
class Meta:
model = User
fields = ['old_password', 'new_password', 'new_password_again']
def validate_old_password(self, value):
if not self.instance.check_password(value):
msg = _('The old password is incorrect')
raise serializers.ValidationError(msg)
return value
@staticmethod
def validate_new_password(value):
from ..utils import check_password_rules
if not check_password_rules(value):
msg = _('Password does not match security rules')
raise serializers.ValidationError(msg)
return value
def validate_new_password_again(self, value):
if value != self.initial_data.get('new_password', ''):
msg = _('The newly set password is inconsistent')
raise serializers.ValidationError(msg)
return value
def update(self, instance, validated_data):
new_password = self.validated_data.get('new_password')
instance.reset_password(new_password)
return instance
class UserUpdatePublicKeySerializer(serializers.ModelSerializer):
public_key_comment = serializers.CharField(
source='get_public_key_comment', required=False, read_only=True, max_length=128
)
public_key_hash_md5 = serializers.CharField(
source='get_public_key_hash_md5', required=False, read_only=True, max_length=128
)
class Meta:
model = User
fields = ['public_key_comment', 'public_key_hash_md5', 'public_key']
extra_kwargs = {
'public_key': {'required': True, 'write_only': True, 'max_length': 2048}
}
@staticmethod
def validate_public_key(value):
if not validate_ssh_public_key(value):
raise serializers.ValidationError(_('Not a valid ssh public key'))
return value
def update(self, instance, validated_data):
new_public_key = self.validated_data.get('public_key')
instance.set_public_key(new_public_key)
return instance
class MiniUserSerializer(serializers.ModelSerializer): class MiniUserSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = User model = User
@ -352,3 +177,46 @@ class InviteSerializer(serializers.Serializer):
queryset=User.objects.exclude(role=User.ROLE.APP) queryset=User.objects.exclude(role=User.ROLE.APP)
) )
role = serializers.ChoiceField(choices=ORG_ROLE.choices) role = serializers.ChoiceField(choices=ORG_ROLE.choices)
class ServiceAccountSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'name', 'access_key']
read_only_fields = ['access_key']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
from authentication.serializers import AccessKeySerializer
self.fields['access_key'] = AccessKeySerializer(read_only=True)
def get_username(self):
return self.initial_data.get('name')
def get_email(self):
name = self.initial_data.get('name')
return '{}@serviceaccount.local'.format(name)
def validate_name(self, name):
email = self.get_email()
username = self.get_username()
if self.instance:
users = User.objects.exclude(id=self.instance.id)
else:
users = User.objects.all()
if users.filter(email=email) or \
users.filter(username=username):
raise serializers.ValidationError(_('name not unique'), code='unique')
return name
def save(self, **kwargs):
self.validated_data['email'] = self.get_email()
self.validated_data['username'] = self.get_username()
self.validated_data['role'] = User.ROLE.APP
return super().save(**kwargs)
def create(self, validated_data):
instance = super().create(validated_data)
instance.create_access_key()
return instance

View File

@ -1,3 +0,0 @@
# -*- coding: utf-8 -*-
#
from .user import *

View File

@ -1,48 +0,0 @@
# -*- coding: utf-8 -*-
#
from django.utils.translation import ugettext as _
from rest_framework import serializers
from ..models import User
from authentication.serializers import AccessKeySerializer
__all__ = ['ServiceAccountSerializer']
class ServiceAccountSerializer(serializers.ModelSerializer):
access_key = AccessKeySerializer(read_only=True)
class Meta:
model = User
fields = ['id', 'name', 'access_key']
read_only_fields = ['access_key']
def get_username(self):
return self.initial_data.get('name')
def get_email(self):
name = self.initial_data.get('name')
return '{}@serviceaccount.local'.format(name)
def validate_name(self, name):
email = self.get_email()
username = self.get_username()
if self.instance:
users = User.objects.exclude(id=self.instance.id)
else:
users = User.objects.all()
if users.filter(email=email) or \
users.filter(username=username):
raise serializers.ValidationError(_('name not unique'), code='unique')
return name
def save(self, **kwargs):
self.validated_data['email'] = self.get_email()
self.validated_data['username'] = self.get_username()
self.validated_data['role'] = User.ROLE.APP
return super().save(**kwargs)
def create(self, validated_data):
instance = super().create(validated_data)
instance.create_access_key()
return instance

View File

@ -15,6 +15,7 @@ router = BulkRouter()
router.register(r'users', api.UserViewSet, 'user') router.register(r'users', api.UserViewSet, 'user')
router.register(r'groups', api.UserGroupViewSet, 'user-group') router.register(r'groups', api.UserGroupViewSet, 'user-group')
router.register(r'users-groups-relations', api.UserUserGroupRelationViewSet, 'users-groups-relation') router.register(r'users-groups-relations', api.UserUserGroupRelationViewSet, 'users-groups-relation')
router.register(r'service-account-registrations', api.ServiceAccountRegistrationViewSet, 'service-account-registration')
urlpatterns = [ urlpatterns = [

View File

@ -1,23 +0,0 @@
#!/usr/bin/env python
# ~*~ coding: utf-8 ~*~
#
from __future__ import absolute_import
from django.urls import path, include
from rest_framework_bulk.routes import BulkRouter
from .. import api_v2 as api
app_name = 'users'
router = BulkRouter()
router.register(r'service-account-registrations',
api.ServiceAccountRegistrationViewSet,
'service-account-registration')
urlpatterns = [
# path('token/', api.UserToken.as_view(), name='user-token'),
]
urlpatterns += router.urls