diff --git a/apps/common/constants/permission_constants.py b/apps/common/constants/permission_constants.py index 22f3c3a5f..92a1978e8 100644 --- a/apps/common/constants/permission_constants.py +++ b/apps/common/constants/permission_constants.py @@ -154,7 +154,7 @@ class PermissionConstants(Enum): USER_READ = Permission(group=Group.USER, operate=Operate.READ, role_list=[RoleConstants.ADMIN, RoleConstants.USER]) USER_CREATE = Permission(group=Group.USER, operate=Operate.CREATE, - role_list=[RoleConstants.ADMIN, RoleConstants.USER]) + role_list=[RoleConstants.ADMIN]) USER_EDIT = Permission(group=Group.USER, operate=Operate.EDIT, role_list=[RoleConstants.ADMIN]) USER_DELETE = Permission(group=Group.USER, operate=Operate.DELETE, role_list=[RoleConstants.ADMIN]) diff --git a/apps/models_provider/urls.py b/apps/models_provider/urls.py index 2f8be7ea5..50f39dcbb 100644 --- a/apps/models_provider/urls.py +++ b/apps/models_provider/urls.py @@ -4,19 +4,14 @@ from . import views app_name = "models_provider" urlpatterns = [ - path('provider', views.Provide.as_view(), name='provide'), - path('provider/model_type_list', views.Provide.ModelTypeList.as_view(), name="provider/model_type_list"), - path('provider/model_list', views.Provide.ModelList.as_view(), name="provider/model_name_list"), - path('provider/model_params_form', views.Provide.ModelParamsForm.as_view(), - name="provider/model_params_form"), - path('provider/model_form', views.Provide.ModelForm.as_view(), - name="provider/model_form"), - path('workspace//model', views.Model.as_view(), name='model'), - path('workspace//model//model_params_form', views.Model.ModelParamsForm.as_view(), - name='model/model_params_form'), - path('workspace//model/', views.Model.Operate.as_view(), name='model/operate'), - path('workspace//model//pause_download', views.Model.PauseDownload.as_view(), - name='model/operate'), - path('workspace//model//meta', views.Model.ModelMeta.as_view(), - name='model/operate/meta'), + path('provider', views.Provide.as_view()), + path('provider/model_type_list', views.Provide.ModelTypeList.as_view()), + path('provider/model_list', views.Provide.ModelList.as_view()), + path('provider/model_params_form', views.Provide.ModelParamsForm.as_view()), + path('provider/model_form', views.Provide.ModelForm.as_view()), + path('workspace//model', views.Model.as_view()), + path('workspace//model//model_params_form', views.Model.ModelParamsForm.as_view()), + path('workspace//model/', views.Model.Operate.as_view()), + path('workspace//model//pause_download', views.Model.PauseDownload.as_view()), + path('workspace//model//meta', views.Model.ModelMeta.as_view()), ] diff --git a/apps/models_provider/views/model.py b/apps/models_provider/views/model.py index f62679496..a53ab10ba 100644 --- a/apps/models_provider/views/model.py +++ b/apps/models_provider/views/model.py @@ -14,7 +14,7 @@ from rest_framework.request import Request from common.auth import TokenAuth from common.auth.authentication import has_permissions from common.constants.permission_constants import PermissionConstants -from common.result import result, DefaultResultSerializer +from common.result import result from common.utils.common import query_params_to_single_dict from models_provider.api.model import ModelCreateAPI, GetModelApi, ModelEditApi, ModelListResponse, DefaultModelResponse from models_provider.api.provide import ProvideApi @@ -25,6 +25,7 @@ class Model(APIView): authentication_classes = [TokenAuth] @extend_schema(methods=['POST'], + summary=_("Create model"), description=_("Create model"), operation_id=_("Create model"), tags=[_("Model")], @@ -38,7 +39,7 @@ class Model(APIView): with_valid=True)) # @extend_schema(methods=['PUT'], - # description=_('Update model'), + # summary=_('Update model'), # operation_id=_('Update model'), # request=ModelEditApi.get_request(), # responses=ModelCreateApi.get_response(), @@ -50,6 +51,7 @@ class Model(APIView): # with_valid=True)) @extend_schema(methods=['GET'], + summary=_('Query model list'), description=_('Query model list'), operation_id=_('Query model list'), parameters=ModelCreateAPI.get_query_params_api(), @@ -66,6 +68,7 @@ class Model(APIView): authentication_classes = [TokenAuth] @extend_schema(methods=['PUT'], + summary=_('Update model'), description=_('Update model'), operation_id=_('Update model'), request=ModelEditApi.get_request(), @@ -79,6 +82,7 @@ class Model(APIView): str(request.user.id))) @extend_schema(methods=['DELETE'], + summary=_('Delete model'), description=_('Delete model'), operation_id=_('Delete model'), parameters=GetModelApi.get_query_params_api(), @@ -90,6 +94,7 @@ class Model(APIView): ModelSerializer.Operate(data={'id': model_id, 'user_id': request.user.id}).delete()) @extend_schema(methods=['GET'], + summary=_('Query model details'), description=_('Query model details'), operation_id=_('Query model details'), parameters=GetModelApi.get_query_params_api(), @@ -104,6 +109,7 @@ class Model(APIView): authentication_classes = [TokenAuth] @extend_schema(methods=['GET'], + summary=_('Get model parameter form'), description=_('Get model parameter form'), operation_id=_('Get model parameter form'), parameters=GetModelApi.get_query_params_api(), @@ -115,6 +121,7 @@ class Model(APIView): ModelSerializer.ModelParams(data={'id': model_id}).get_model_params()) @extend_schema(methods=['PUT'], + summary=_('Save model parameter form'), description=_('Save model parameter form'), operation_id=_('Save model parameter form'), parameters=GetModelApi.get_query_params_api(), @@ -130,6 +137,8 @@ class Model(APIView): authentication_classes = [TokenAuth] @extend_schema(methods=['GET'], + summary=_( + 'Query model meta information, this interface does not carry authentication information'), description=_( 'Query model meta information, this interface does not carry authentication information'), operation_id=_( @@ -146,6 +155,7 @@ class Model(APIView): authentication_classes = [TokenAuth] @extend_schema(methods=['PUT'], + summary=_('Pause model download'), description=_('Pause model download'), operation_id=_('Pause model download'), parameters=GetModelApi.get_query_params_api(), diff --git a/apps/models_provider/views/provide.py b/apps/models_provider/views/provide.py index d4dd8a73c..18cfadc62 100644 --- a/apps/models_provider/views/provide.py +++ b/apps/models_provider/views/provide.py @@ -18,6 +18,7 @@ class Provide(APIView): authentication_classes = [TokenAuth] @extend_schema(methods=['GET'], + summary=_('Get a list of model suppliers'), description=_('Get a list of model suppliers'), operation_id=_('Get a list of model suppliers'), responses=ProvideApi.get_response(), @@ -40,6 +41,7 @@ class Provide(APIView): authentication_classes = [TokenAuth] @extend_schema(methods=['GET'], + summary=_('Get a list of model types'), description=_('Get a list of model types'), operation_id=_('Get a list of model types'), parameters=ProvideApi.ModelTypeList.get_query_params_api(), @@ -54,6 +56,7 @@ class Provide(APIView): authentication_classes = [TokenAuth] @extend_schema(methods=['GET'], + summary=_('Example of obtaining model list'), description=_('Example of obtaining model list'), operation_id=_('Example of obtaining model list'), parameters=ProvideApi.ModelList.get_query_params_api(), @@ -72,6 +75,7 @@ class Provide(APIView): authentication_classes = [TokenAuth] @extend_schema(methods=['GET'], + summary=_('Get model default parameters'), description=_('Get model default parameters'), operation_id=_('Get model default parameters'), parameters=ProvideApi.ModelParamsForm.get_query_params_api(), @@ -89,6 +93,7 @@ class Provide(APIView): authentication_classes = [TokenAuth] @extend_schema(methods=['GET'], + summary=_('Get the model creation form'), description=_('Get the model creation form'), operation_id=_('Get the model creation form'), parameters=ProvideApi.ModelParamsForm.get_query_params_api(), diff --git a/apps/users/api/user.py b/apps/users/api/user.py index 415ea4913..8c7dcfa0f 100644 --- a/apps/users/api/user.py +++ b/apps/users/api/user.py @@ -11,7 +11,10 @@ from drf_spectacular.utils import OpenApiParameter from common.mixins.api_mixin import APIMixin from common.result import ResultSerializer -from users.serializers.user import UserProfileResponse, CreateUserSerializer +from users.serializers.user import UserProfileResponse, CreateUserSerializer, UserManageSerializer, \ + UserInstanceSerializer +from django.utils.translation import gettext_lazy as _ +from rest_framework import serializers class ApiUserProfileResponse(ResultSerializer): @@ -29,6 +32,87 @@ class UserProfileAPI(APIMixin): def get_request(): return CreateUserSerializer + @staticmethod + def get_parameters(): + return [OpenApiParameter( + name="user_id", + description=_('User ID'), + type=OpenApiTypes.STR, + location=OpenApiParameter.PATH, + required=True, + )] + + +class EditUserApi(APIMixin): + @staticmethod + def get_parameters(): + return [OpenApiParameter( + name="user_id", + description=_('User ID'), + type=OpenApiTypes.STR, + location=OpenApiParameter.PATH, + required=True, + )] + + @staticmethod + def get_request(): + return UserManageSerializer.UserEditInstance + + +class DeleteUserApi(APIMixin): + @staticmethod + def get_parameters(): + return [OpenApiParameter( + name="user_id", + description=_('User ID'), + type=OpenApiTypes.STR, + location=OpenApiParameter.PATH, + required=True, + )] + + +class ChangeUserPasswordApi(APIMixin): + @staticmethod + def get_request(): + return UserManageSerializer.RePasswordInstance + + +class UserListResponse(ResultSerializer): + def get_data(self): + return serializers.ListSerializer(child=UserInstanceSerializer()) + + +class UserPageApi(APIMixin): + @staticmethod + def get_parameters(): + return [OpenApiParameter( + name="email_or_username", + description=_('Email or Username'), + type=OpenApiTypes.STR, + location=OpenApiParameter.QUERY, + required=False, + )] + + @staticmethod + def get_response(): + return UserListResponse + + +class UserListApi(APIMixin): + @staticmethod + def get_parameters(): + return [OpenApiParameter( + name="workspace_id", + description=_('Workspace ID'), + type=OpenApiTypes.STR, + location=OpenApiParameter.PATH, + required=False, + )] + + @staticmethod + def get_response(): + return UserListResponse + class TestWorkspacePermissionUserApi(APIMixin): @staticmethod diff --git a/apps/users/migrations/0001_initial.py b/apps/users/migrations/0001_initial.py index 875e2dcb8..51fa11560 100644 --- a/apps/users/migrations/0001_initial.py +++ b/apps/users/migrations/0001_initial.py @@ -5,13 +5,15 @@ from django.db import migrations, models from common.constants.permission_constants import RoleConstants from common.utils.common import password_encrypt +from maxkb.const import CONFIG +default_password = CONFIG.get('default_password', 'MaxKB@123..') def insert_default_data(apps, schema_editor): UserModel = apps.get_model('users', 'User') UserModel.objects.create(id='f0dd8f71-e4ee-11ee-8c84-a8a1595801ab', email='', username='admin', nick_name="系统管理员", - password=password_encrypt('MaxKB@123..'), + password=password_encrypt(default_password), role=RoleConstants.ADMIN.name, is_active=True) diff --git a/apps/users/serializers/user.py b/apps/users/serializers/user.py index c3ab94f9c..cea6dacd4 100644 --- a/apps/users/serializers/user.py +++ b/apps/users/serializers/user.py @@ -9,16 +9,23 @@ import re from django.db import transaction -from django.db.models import QuerySet, Q +from django.db.models import Q, QuerySet from rest_framework import serializers import uuid_utils.compat as uuid from common.constants.exception_code_constants import ExceptionCodeConstants from common.constants.permission_constants import RoleConstants, Auth +from common.db.search import page_search +from common.exception.app_exception import AppApiException from common.utils.common import valid_license, password_encrypt from users.models import User from django.utils.translation import gettext_lazy as _ from django.core import validators +PASSWORD_REGEX = re.compile( + r"^(?![a-zA-Z]+$)(?![A-Z0-9]+$)(?![A-Z_!@#$%^&*`~.()-+=]+$)(?![a-z0-9]+$)(?![a-z_!@#$%^&*`~()-+=]+$)" + r"(?![0-9_!@#$%^&*`~()-+=]+$)[a-zA-Z0-9_!@#$%^&*`~.()-+=]{6,20}$" +) + class UserProfileResponse(serializers.ModelSerializer): is_edit_password = serializers.BooleanField(required=True, label=_('Is Edit Password')) @@ -46,15 +53,23 @@ class UserProfileSerializer(serializers.Serializer): @param auth: 认证对象 @return: """ + return { + 'id': user.id, + 'username': user.username, + 'nick_name': user.nick_name, + 'email': user.email, + 'role': auth.role_list, + 'permissions': auth.permission_list, + 'is_edit_password': user.role == RoleConstants.ADMIN.name and user.password == 'd880e722c47a34d8e9fce789fc62389d', + 'language': user.language, + } - return {'id': user.id, - 'username': user.username, - 'nick_name': user.nick_name, - 'email': user.email, - 'role': auth.role_list, - 'permissions': auth.permission_list, - 'is_edit_password': user.password == 'd880e722c47a34d8e9fce789fc62389d' if user.role == 'ADMIN' else False, - 'language': user.language} + +class UserInstanceSerializer(serializers.ModelSerializer): + class Meta: + model = User + fields = ['id', 'username', 'email', 'phone', 'is_active', 'role', 'nick_name', 'create_time', 'update_time', + 'source'] class UserManageSerializer(serializers.Serializer): @@ -62,54 +77,249 @@ class UserManageSerializer(serializers.Serializer): email = serializers.EmailField( required=True, label=_("Email"), - validators=[validators.EmailValidator(message=ExceptionCodeConstants.EMAIL_FORMAT_ERROR.value.message, - code=ExceptionCodeConstants.EMAIL_FORMAT_ERROR.value.code)]) - - username = serializers.CharField(required=True, - label=_("Username"), - max_length=20, - min_length=6, - validators=[ - validators.RegexValidator(regex=re.compile("^.{6,20}$"), - message=_( - 'Username must be 6-20 characters long')) - ]) - password = serializers.CharField(required=True, label=_("Password"), max_length=20, min_length=6, - validators=[validators.RegexValidator(regex=re.compile( - "^(?![a-zA-Z]+$)(?![A-Z0-9]+$)(?![A-Z_!@#$%^&*`~.()-+=]+$)(?![a-z0-9]+$)(?![a-z_!@#$%^&*`~()-+=]+$)" - "(?![0-9_!@#$%^&*`~()-+=]+$)[a-zA-Z0-9_!@#$%^&*`~.()-+=]{6,20}$") - , message=_( - "The password must be 6-20 characters long and must be a combination of letters, numbers, and special characters."))]) - - nick_name = serializers.CharField(required=False, label=_("Nick name"), max_length=64, - allow_null=True, allow_blank=True) - phone = serializers.CharField(required=False, label=_("Phone"), max_length=20, - allow_null=True, allow_blank=True) + validators=[validators.EmailValidator( + message=ExceptionCodeConstants.EMAIL_FORMAT_ERROR.value.message, + code=ExceptionCodeConstants.EMAIL_FORMAT_ERROR.value.code + )] + ) + username = serializers.CharField( + required=True, + label=_("Username"), + max_length=20, + min_length=6, + validators=[ + validators.RegexValidator( + regex=re.compile("^.{6,20}$"), + message=_('Username must be 6-20 characters long') + ) + ] + ) + password = serializers.CharField( + required=True, + label=_("Password"), + max_length=20, + min_length=6, + validators=[ + validators.RegexValidator( + regex=PASSWORD_REGEX, + message=_( + "The password must be 6-20 characters long and must be a combination of letters, numbers, and special characters." + ) + ) + ] + ) + nick_name = serializers.CharField( + required=False, + label=_("Nick name"), + max_length=64, + allow_null=True, + allow_blank=True + ) + phone = serializers.CharField( + required=False, + label=_("Phone"), + max_length=20, + allow_null=True, + allow_blank=True + ) def is_valid(self, *, raise_exception=True): super().is_valid(raise_exception=True) + self._check_unique_username_and_email() + + def _check_unique_username_and_email(self): username = self.data.get('username') email = self.data.get('email') - u = QuerySet(User).filter(Q(username=username) | Q(email=email)).first() - if u is not None: - if u.email == email: + user = User.objects.filter(Q(username=username) | Q(email=email)).first() + if user: + if user.email == email: raise ExceptionCodeConstants.EMAIL_IS_EXIST.value.to_app_api_exception() - if u.username == username: + if user.username == username: raise ExceptionCodeConstants.USERNAME_IS_EXIST.value.to_app_api_exception() + class Query(serializers.Serializer): + email_or_username = serializers.CharField(required=False, allow_null=True, + label=_('Email or username')) + + def get_query_set(self): + email_or_username = self.data.get('email_or_username') + query_set = QuerySet(User) + if email_or_username is not None: + query_set = query_set.filter( + Q(username__contains=email_or_username) | Q(email__contains=email_or_username)) + query_set = query_set.order_by("-create_time") + return query_set + + def list(self, with_valid=True): + if with_valid: + self.is_valid(raise_exception=True) + return [{'id': user_model.id, 'username': user_model.username, 'email': user_model.email} for user_model in + self.get_query_set()] + + def page(self, current_page: int, page_size: int, with_valid=True): + if with_valid: + self.is_valid(raise_exception=True) + return page_search(current_page, page_size, + self.get_query_set(), + post_records_handler=lambda u: UserInstanceSerializer(u).data) + @valid_license(model=User, count=2, message=_( 'The community version supports up to 2 users. If you need more users, please contact us (https://fit2cloud.com/).')) @transaction.atomic def save(self, instance, with_valid=True): if with_valid: - UserManageSerializer.UserInstance(data=instance).is_valid(raise_exception=True) + self.UserInstance(data=instance).is_valid(raise_exception=True) - user = User(id=uuid.uuid7(), email=instance.get('email'), - phone="" if instance.get('phone') is None else instance.get('phone'), - nick_name="" if instance.get('nick_name') is None else instance.get('nick_name') - , username=instance.get('username'), password=password_encrypt(instance.get('password')), - role=RoleConstants.USER.name, source="LOCAL", - is_active=True) + user = User( + id=uuid.uuid7(), + email=instance.get('email'), + phone=instance.get('phone', ''), + nick_name=instance.get('nick_name', ''), + username=instance.get('username'), + password=password_encrypt(instance.get('password')), + role=RoleConstants.USER.name, + source="LOCAL", + is_active=True + ) user.save() - return UserProfileSerializer(user).data + return UserInstanceSerializer(user).data + + class UserEditInstance(serializers.Serializer): + email = serializers.EmailField( + required=False, + label=_("Email"), + validators=[validators.EmailValidator( + message=ExceptionCodeConstants.EMAIL_FORMAT_ERROR.value.message, + code=ExceptionCodeConstants.EMAIL_FORMAT_ERROR.value.code + )] + ) + nick_name = serializers.CharField( + required=False, + label=_("Name"), + max_length=64, + allow_null=True, + allow_blank=True + ) + phone = serializers.CharField( + required=False, + label=_("Phone"), + max_length=20, + allow_null=True, + allow_blank=True + ) + is_active = serializers.BooleanField( + required=False, + label=_("Is Active") + ) + + def is_valid(self, *, user_id=None, raise_exception=False): + super().is_valid(raise_exception=True) + self._check_unique_email(user_id) + + def _check_unique_email(self, user_id): + email = self.data.get('email') + if email and User.objects.filter(email=email).exclude(id=user_id).exists(): + raise AppApiException(1004, _('Email is already in use')) + + class RePasswordInstance(serializers.Serializer): + password = serializers.CharField( + required=True, + label=_("Password"), + max_length=20, + min_length=6, + validators=[ + validators.RegexValidator( + regex=PASSWORD_REGEX, + message=_( + "The password must be 6-20 characters long and must be a combination of letters, numbers, and special characters." + ) + ) + ] + ) + re_password = serializers.CharField( + required=True, + label=_("Re Password"), + validators=[ + validators.RegexValidator( + regex=PASSWORD_REGEX, + message=_( + "The confirmation password must be 6-20 characters long and must be a combination of letters, numbers, and special characters." + ) + ) + ] + ) + + def is_valid(self, *, raise_exception=False): + super().is_valid(raise_exception=True) + self._check_passwords_match() + + def _check_passwords_match(self): + if self.data.get('password') != self.data.get('re_password'): + raise ExceptionCodeConstants.PASSWORD_NOT_EQ_RE_PASSWORD.value.to_app_api_exception() + + class Operate(serializers.Serializer): + id = serializers.UUIDField(required=True, label=_('User ID')) + + def is_valid(self, *, raise_exception=False): + super().is_valid(raise_exception=True) + self._check_user_exists() + + def _check_user_exists(self): + if not User.objects.filter(id=self.data.get('id')).exists(): + raise AppApiException(1004, _('User does not exist')) + + @transaction.atomic + def delete(self, with_valid=True): + if with_valid: + self.is_valid(raise_exception=True) + self._check_not_admin() + user_id = self.data.get('id') + # TODO 需要删除授权关系 + User.objects.filter(id=user_id).delete() + return True + + def _check_not_admin(self): + user = User.objects.filter(id=self.data.get('id')).first() + if user.role == RoleConstants.ADMIN.name: + raise AppApiException(1004, _('Unable to delete administrator')) + + def edit(self, instance, with_valid=True): + if with_valid: + self.is_valid(raise_exception=True) + UserManageSerializer.UserEditInstance(data=instance).is_valid(user_id=self.data.get('id'), + raise_exception=True) + user = User.objects.filter(id=self.data.get('id')).first() + self._check_admin_modification(user, instance) + self._update_user_fields(user, instance) + user.save() + return UserInstanceSerializer(user).data + + @staticmethod + def _check_admin_modification(user, instance): + if user.role == RoleConstants.ADMIN.name and 'is_active' in instance and instance.get( + 'is_active') is not None: + raise AppApiException(1004, _('Cannot modify administrator status')) + + @staticmethod + def _update_user_fields(user, instance): + update_keys = ['email', 'nick_name', 'phone', 'is_active'] + for key in update_keys: + if key in instance and instance.get(key) is not None: + setattr(user, key, instance.get(key)) + + def one(self, with_valid=True): + if with_valid: + self.is_valid(raise_exception=True) + user = User.objects.filter(id=self.data.get('id')).first() + return UserInstanceSerializer(user).data + + def re_password(self, instance, with_valid=True): + if with_valid: + self.is_valid(raise_exception=True) + UserManageSerializer.RePasswordInstance(data=instance).is_valid(raise_exception=True) + user = User.objects.filter(id=self.data.get('id')).first() + user.password = password_encrypt(instance.get('password')) + user.save() + return True + diff --git a/apps/users/urls.py b/apps/users/urls.py index 43ff85747..19f88bf15 100644 --- a/apps/users/urls.py +++ b/apps/users/urls.py @@ -11,9 +11,9 @@ urlpatterns = [ path('workspace//user/profile', views.TestWorkspacePermissionUserView.as_view(), name="test_workspace_id_permission"), path("user_manage", views.UserManage.as_view(), name="user_manage"), - # path("user_manage/", views.UserManage.Operate.as_view(), name="user_manage_operate"), - # path("user_manage//re_password", views.UserManage.RePassword.as_view(), - # name="user_manage_re_password"), - # path("user_manage//", views.UserManage.Page.as_view(), - # name="user_manage_re_password"), + path("user_manage/", views.UserManage.Operate.as_view(), name="user_manage_operate"), + path("user_manage//re_password", views.UserManage.RePassword.as_view(), + name="user_manage_re_password"), + path("user_manage//", views.UserManage.Page.as_view(), + name="user_manage_page"), ] diff --git a/apps/users/views/login.py b/apps/users/views/login.py index ccf51b865..9a09ab843 100644 --- a/apps/users/views/login.py +++ b/apps/users/views/login.py @@ -19,6 +19,7 @@ from users.serializers.login import LoginSerializer, CaptchaSerializer class LoginView(APIView): @extend_schema(methods=['POST'], description=_("Log in"), + summary=_("Log in"), operation_id=_("Log in"), tags=[_("User management")], request=LoginAPI.get_request(), @@ -29,6 +30,7 @@ class LoginView(APIView): class CaptchaView(APIView): @extend_schema(methods=['GET'], + summary=_("Get captcha"), description=_("Get captcha"), operation_id=_("Get captcha"), tags=[_("User management")], diff --git a/apps/users/views/user.py b/apps/users/views/user.py index 502ee3784..f5f591a4c 100644 --- a/apps/users/views/user.py +++ b/apps/users/views/user.py @@ -15,7 +15,9 @@ from common.auth.authenticate import TokenAuth from common.auth.authentication import has_permissions from common.constants.permission_constants import PermissionConstants, Permission, Group, Operate from common.result import result -from users.api.user import UserProfileAPI, TestWorkspacePermissionUserApi +from models_provider.api.model import DefaultModelResponse +from users.api.user import UserProfileAPI, TestWorkspacePermissionUserApi, DeleteUserApi, EditUserApi, \ + ChangeUserPasswordApi, UserPageApi, UserListApi from users.serializers.user import UserProfileSerializer, UserManageSerializer @@ -23,6 +25,7 @@ class UserProfileView(APIView): authentication_classes = [TokenAuth] @extend_schema(methods=['GET'], + summary=_("Get current user information"), description=_("Get current user information"), operation_id=_("Get current user information"), tags=[_("User management")], @@ -35,6 +38,7 @@ class TestPermissionsUserView(APIView): authentication_classes = [TokenAuth] @extend_schema(methods=['GET'], + summary=_("Get current user information"), description=_("Get current user information"), operation_id="测试", tags=[_("User management")], @@ -48,6 +52,7 @@ class TestWorkspacePermissionUserView(APIView): authentication_classes = [TokenAuth] @extend_schema(methods=['GET'], + summary="针对工作空间下权限校验", description="针对工作空间下权限校验", operation_id="针对工作空间下权限校验", tags=[_("User management")], @@ -62,6 +67,7 @@ class UserManage(APIView): authentication_classes = [TokenAuth] @extend_schema(methods=['POST'], + summary=_("Create user"), description=_("Create user"), operation_id=_("Create user"), tags=[_("User management")], @@ -70,3 +76,73 @@ class UserManage(APIView): @has_permissions(PermissionConstants.USER_CREATE) def post(self, request: Request): return result.success(UserManageSerializer().save(request.data)) + + class Operate(APIView): + authentication_classes = [TokenAuth] + + @extend_schema(methods=['DELETE'], + description=_("Delete user"), + summary=_("Delete user"), + operation_id=_("Delete user"), + tags=[_("User management")], + parameters=DeleteUserApi.get_parameters(), + responses=DefaultModelResponse.get_response()) + @has_permissions(PermissionConstants.USER_DELETE) + def delete(self, request: Request, user_id): + return result.success(UserManageSerializer.Operate(data={'id': user_id}).delete(with_valid=True)) + + @extend_schema(methods=['GET'], + summary=_("Get user information"), + description=_("Get user information"), + operation_id=_("Get user information"), + tags=[_("User management")], + request=DeleteUserApi.get_parameters(), + responses=UserProfileAPI.get_response()) + @has_permissions(PermissionConstants.USER_READ) + def get(self, request: Request, user_id): + return result.success(UserManageSerializer.Operate(data={'id': user_id}).one(with_valid=True)) + + @extend_schema(methods=['PUT'], + summary=_("Update user information"), + description=_("Update user information"), + operation_id=_("Update user information"), + tags=[_("User management")], + parameters=DeleteUserApi.get_parameters(), + request=EditUserApi.get_request(), + responses=UserProfileAPI.get_response()) + @has_permissions(PermissionConstants.USER_EDIT) + def put(self, request: Request, user_id): + return result.success( + UserManageSerializer.Operate(data={'id': user_id}).edit(request.data, with_valid=True)) + + class RePassword(APIView): + authentication_classes = [TokenAuth] + + @extend_schema(methods=['PUT'], + summary=_("Change password"), + description=_("Change password"), + operation_id=_("Change password"), + tags=[_("User management")], + parameters=DeleteUserApi.get_parameters(), + request=ChangeUserPasswordApi.get_request(), + responses=DefaultModelResponse.get_response()) + def put(self, request: Request, user_id): + return result.success( + UserManageSerializer.Operate(data={'id': user_id}).re_password(request.data, with_valid=True)) + + class Page(APIView): + authentication_classes = [TokenAuth] + + @extend_schema(methods=['GET'], + summary=_("Get user paginated list"), + description=_("Get user paginated list"), + operation_id=_("Get user paginated list"), + tags=[_("User management")], + parameters=UserPageApi.get_parameters(), + responses=UserPageApi.get_response()) + @has_permissions(PermissionConstants.USER_READ) + def get(self, request: Request, current_page, page_size): + d = UserManageSerializer.Query( + data={'email_or_username': request.query_params.get('email_or_username', None), + 'user_id': str(request.user.id)}) + return result.success(d.page(current_page, page_size))