diff --git a/apps/users/serializers/user.py b/apps/users/serializers/user.py index bdb8a3a1c..4debf9633 100644 --- a/apps/users/serializers/user.py +++ b/apps/users/serializers/user.py @@ -12,11 +12,15 @@ import random import re from collections import defaultdict from itertools import product + +from django.core.cache import cache from django.core.mail.backends.smtp import EmailBackend from django.db import transaction from django.db.models import Q, QuerySet from rest_framework import serializers import uuid_utils.compat as uuid + +from common.constants.cache_version import Cache_Version from common.constants.exception_code_constants import ExceptionCodeConstants from common.constants.permission_constants import RoleConstants, Auth from common.database_model_manage.database_model_manage import DatabaseModelManage @@ -36,6 +40,8 @@ PASSWORD_REGEX = re.compile( r"(?![0-9_!@#$%^&*`~()-+=]+$)[a-zA-Z0-9_!@#$%^&*`~.()-+=]{6,20}$" ) +version, get_key = Cache_Version.SYSTEM.value + class UserProfileResponse(serializers.ModelSerializer): is_edit_password = serializers.BooleanField(required=True, label=_('Is Edit Password')) @@ -481,14 +487,13 @@ class RePasswordSerializer(serializers.Serializer): def is_valid(self, *, raise_exception=False): super().is_valid(raise_exception=True) email = self.data.get("email") - # TODO 删除缓存 - # cache_code = user_cache.get(email + ':reset_password') + cache_code = cache.get(get_key(email + ':reset_password'), version=version) if self.data.get('password') != self.data.get('re_password'): raise AppApiException(ExceptionCodeConstants.PASSWORD_NOT_EQ_RE_PASSWORD.value.code, ExceptionCodeConstants.PASSWORD_NOT_EQ_RE_PASSWORD.value.message) - # if cache_code != self.data.get('code'): - # raise AppApiException(ExceptionCodeConstants.CODE_ERROR.value.code, - # ExceptionCodeConstants.CODE_ERROR.value.message) + if cache_code != self.data.get('code'): + raise AppApiException(ExceptionCodeConstants.CODE_ERROR.value.code, + ExceptionCodeConstants.CODE_ERROR.value.message) return True def reset_password(self): @@ -502,7 +507,7 @@ class RePasswordSerializer(serializers.Serializer): password=password_encrypt(self.data.get('password'))) code_cache_key = email + ":reset_password" # 删除验证码缓存 - # user_cache.delete(code_cache_key) + cache.delete(code_cache_key, version=version) return True @@ -531,7 +536,7 @@ class SendEmailSerializer(serializers.Serializer): raise ExceptionCodeConstants.EMAIL_IS_EXIST.value.to_app_api_exception() code_cache_key = self.data.get('email') + ":" + self.data.get("type") code_cache_key_lock = code_cache_key + "_lock" - ttl = None # user_cache.ttl(code_cache_key_lock) + ttl = cache.ttl(code_cache_key_lock) if ttl is not None: raise AppApiException(500, _("Do not send emails again within {seconds} seconds").format( seconds=int(ttl.total_seconds()))) @@ -558,10 +563,10 @@ class SendEmailSerializer(serializers.Serializer): code_cache_key = email + ":" + state code_cache_key_lock = code_cache_key + "_lock" # 设置缓存 - # user_cache.set(code_cache_key_lock, code, timeout=datetime.timedelta(minutes=1)) + cache.set(get_key(code_cache_key_lock), code, timeout=datetime.timedelta(minutes=1), version=version) system_setting = QuerySet(SystemSetting).filter(type=SettingType.EMAIL.value).first() if system_setting is None: - # user_cache.delete(code_cache_key_lock) + cache.delete(get_key(code_cache_key_lock), version=version) raise AppApiException(1004, _("The email service has not been set up. Please contact the administrator to set up the email service in [Email Settings].")) try: @@ -581,9 +586,9 @@ class SendEmailSerializer(serializers.Serializer): from_email=system_setting.meta.get('from_email'), recipient_list=[email], fail_silently=False, connection=connection) except Exception as e: - # user_cache.delete(code_cache_key_lock) + cache.delete(get_key(code_cache_key_lock)) raise AppApiException(500, f"{str(e)}" + _("Email sending failed")) - # user_cache.set(code_cache_key, code, timeout=datetime.timedelta(minutes=30)) + cache.set(get_key(code_cache_key), code, timeout=datetime.timedelta(minutes=30), version=version) return True @@ -609,8 +614,7 @@ class CheckCodeSerializer(serializers.Serializer): def is_valid(self, *, raise_exception=False): super().is_valid() - #TODO 这里的缓存 需要重新设计 - value = None#user_cache.get(self.data.get("email") + ":" + self.data.get("type")) + value = cache.get(get_key(self.data.get("email") + ":" + self.data.get("type")), version=version) if value is None or value != self.data.get("code"): raise ExceptionCodeConstants.CODE_ERROR.value.to_app_api_exception() return True diff --git a/apps/users/urls.py b/apps/users/urls.py index 636fcbec0..81edb9886 100644 --- a/apps/users/urls.py +++ b/apps/users/urls.py @@ -13,6 +13,7 @@ urlpatterns = [ path("user/check_code", views.CheckCode.as_view(), name='check_code'), path("user/re_password", views.RePasswordView.as_view(), name='re_password'), path("user/current/send_email", views.SendEmailToCurrentUserView.as_view(), name="send_email_current"), + path("user/current/reset_password", views.ResetCurrentUserPasswordView.as_view(), name="reset_password_current"), path('workspace//user_list', views.WorkspaceUserListView.as_view(), name="test_workspace_id_permission"), path('workspace//user/profile', views.TestWorkspacePermissionUserView.as_view(), diff --git a/apps/users/views/user.py b/apps/users/views/user.py index c0e227d0a..b99bc224b 100644 --- a/apps/users/views/user.py +++ b/apps/users/views/user.py @@ -6,6 +6,7 @@ @date:2025/4/14 19:25 @desc: """ +from django.core.cache import cache from django.db.models import QuerySet from django.utils.translation import gettext_lazy as _ from drf_spectacular.utils import extend_schema @@ -14,6 +15,7 @@ from rest_framework.views import APIView from common.auth.authenticate import TokenAuth from common.auth.authentication import has_permissions +from common.constants.cache_version import Cache_Version from common.constants.permission_constants import PermissionConstants, Permission, Group, Operate from common.log.log import log from common.result import result @@ -295,3 +297,27 @@ class SendEmailToCurrentUserView(APIView): serializer_obj = SendEmailSerializer(data={'email': request.user.email, 'type': "reset_password"}) if serializer_obj.is_valid(raise_exception=True): return result.success(serializer_obj.send()) + + +class ResetCurrentUserPasswordView(APIView): + authentication_classes = [TokenAuth] + + @extend_schema(methods=['POST'], + summary=_("Modify current user password"), + description=_("Modify current user password"), + operation_id=_("Modify current user password"), # type: ignore + tags=[_("User Management")], # type: ignore + request=ResetPasswordAPI.get_request(), + responses=DefaultModelResponse.get_response()) + @log(menu='User management', operate='Modify current user password', + get_operation_object=lambda r, k: {'name': r.user.username}, + get_details=get_re_password_details) + def post(self, request: Request): + data = {'email': request.user.email} + data.update(request.data) + serializer_obj = RePasswordSerializer(data=data) + if serializer_obj.reset_password(): + version, get_key = Cache_Version.TOKEN.value + cache.delete(get_key(token=request.auth), version=version) + return result.success(True) + return result.error(_("Failed to change password"))