diff --git a/src/django-master/accounts/admin.py b/src/django-master/accounts/admin.py index 5989ae5..d52678e 100644 --- a/src/django-master/accounts/admin.py +++ b/src/django-master/accounts/admin.py @@ -13,6 +13,7 @@ from django.contrib.auth.forms import UsernameField # 导入国际化翻译工 from django.utils.translation import gettext_lazy as _ >>>>>>> LXY_branch +<<<<<<< HEAD <<<<<<< HEAD # 本地应用导入 # Register your models here. @@ -20,6 +21,9 @@ from django.utils.translation import gettext_lazy as _ from .models import BlogUser # 导入自定义用户模型 ======= # 导入自定义用户模型 +======= +# jyn:导入自定义用户模型 +>>>>>>> JYN_branch from .models import BlogUser >>>>>>> JYN_branch @@ -44,6 +48,7 @@ class BlogUserCreationForm(forms.ModelForm): 自定义用户创建表单,用于在管理员界面添加新用户 继承自ModelForm,提供密码验证功能 """ +<<<<<<< HEAD # 密码字段,使用PasswordInput小部件确保输入不可见 ======= from .models import BlogUser# 导入当前应用下的BlogUser模型(自定义用户模型) @@ -55,16 +60,23 @@ class BlogUserCreationForm(forms.ModelForm): # 定义两个密码字段,使用 ======= class BlogUserCreationForm(forms.ModelForm): # lxy定义两个密码字段,使用PasswordInput小部件隐藏输入 >>>>>>> LXY_branch +======= + # jyn:密码字段,使用PasswordInput小部件确保输入不可见 +>>>>>>> JYN_branch password1 = forms.CharField(label=_('password'), widget=forms.PasswordInput) - # 确认密码字段,用于验证两次输入的密码是否一致 + # jyn:确认密码字段,用于验证两次输入的密码是否一致 password2 = forms.CharField(label=_('Enter password again'), widget=forms.PasswordInput) class Meta: <<<<<<< HEAD +<<<<<<< HEAD <<<<<<< HEAD # 指定关联的模型 +======= + # jyn:指定关联的模型 +>>>>>>> JYN_branch model = BlogUser - # 表单中包含的字段,这里只显示邮箱 + # jyn:表单中包含的字段,这里只显示邮箱 fields = ('email',) >>>>>>> JYN_branch @@ -95,7 +107,11 @@ class BlogUserCreationForm(forms.ModelForm): # lxy定义两个密码字段,使 """ password1 = self.cleaned_data.get("password1") password2 = self.cleaned_data.get("password2") +<<<<<<< HEAD # 检查密码是否存在且不一致 +>>>>>>> JYN_branch +======= + # jyn:检查密码是否存在且不一致 >>>>>>> JYN_branch if password1 and password2 and password1 != password2: <<<<<<< HEAD @@ -120,12 +136,12 @@ class BlogUserCreationForm(forms.ModelForm): # lxy定义两个密码字段,使 重写保存方法,确保密码以哈希形式存储 而不是明文存储 """ - # 先调用父类方法获取用户对象,但不立即保存到数据库 + # jyn:先调用父类方法获取用户对象,但不立即保存到数据库 user = super().save(commit=False) - # 使用set_password方法对密码进行哈希处理 + # jyn:使用set_password方法对密码进行哈希处理 user.set_password(self.cleaned_data["password1"]) if commit: - # 标记用户来源为管理员站点 + # jyn:标记用户来源为管理员站点 user.source = 'adminsite' user.save() ======= @@ -205,11 +221,11 @@ class BlogUserAdmin(UserAdmin): 继承自Django内置的UserChangeForm """ class Meta: - # 指定关联的模型 + # jyn:指定关联的模型 model = BlogUser - # 显示所有字段 + # jyn:显示所有字段 fields = '__all__' - # 指定用户名字段的处理类 + # jyn:指定用户名字段的处理类 field_classes = {'username': UsernameField} def __init__(self, *args, **kwargs): @@ -222,10 +238,11 @@ class BlogUserAdmin(UserAdmin): 自定义用户管理员类,用于在Django管理后台配置用户模型的显示和操作 继承自Django内置的UserAdmin """ - # 指定编辑用户时使用的表单 + # jyn:指定编辑用户时使用的表单 form = BlogUserChangeForm - # 指定添加用户时使用的表单 + # jyn:指定添加用户时使用的表单 add_form = BlogUserCreationForm +<<<<<<< HEAD # 列表页面显示的字段 ======= model = BlogUser # 关联的模型是BlogUser @@ -250,6 +267,9 @@ class BlogUserAdmin(UserAdmin): form = BlogUserChangeForm#lxy指定修改用户时使用的表单 add_form = BlogUserCreationForm# lxy指定创建用户时使用的表单 >>>>>>> LXY_branch +======= + # jyn:列表页面显示的字段 +>>>>>>> JYN_branch list_display = ( 'id', 'nickname', @@ -260,8 +280,9 @@ class BlogUserAdmin(UserAdmin): <<<<<<< HEAD 'source' ) - # 列表页面中可点击跳转的字段 + # jyn:列表页面中可点击跳转的字段 list_display_links = ('id', 'username') +<<<<<<< HEAD # 排序方式,按id降序排列(最新的用户在前) ordering = ('-id',) >>>>>>> JYN_branch @@ -275,3 +296,7 @@ class BlogUserAdmin(UserAdmin): list_display_links = ('id', 'username')#lxy列表页中可点击跳转的字段 ordering = ('-id',)#lxy列表页的排序方式(按ID倒序) >>>>>>> LXY_branch +======= + # jyn:排序方式,按id降序排列(最新的用户在前) + ordering = ('-id',) +>>>>>>> JYN_branch diff --git a/src/django-master/accounts/apps.py b/src/django-master/accounts/apps.py index 4cba08b..087d079 100644 --- a/src/django-master/accounts/apps.py +++ b/src/django-master/accounts/apps.py @@ -18,6 +18,7 @@ class AccountsConfig(AppConfig): 每个Django应用都需要一个配置类,用于设置应用的各种属性和行为 通常放在应用目录下的apps.py文件中 """ +<<<<<<< HEAD # 应用的名称,必须与应用目录名一致 # 这个名称会被Django用来识别和管理应用 name = 'accounts' @@ -36,3 +37,8 @@ from django.apps import AppConfig#lxy导入 Django 框架中用于应用配置 class AccountsConfig(AppConfig):#lxy定义 AccountsConfig 类,继承自 AppConfig,用于对 accounts 应用进行自定义配置 name = 'accounts'#lxy指定该应用的名称为 accounts,Django 会通过这个名称来识别和管理该应用 >>>>>>> LXY_branch +======= + # jyn:应用的名称,必须与应用目录名一致 + # jyn:这个名称会被Django用来识别和管理应用 + name = 'accounts' +>>>>>>> JYN_branch diff --git a/src/django-master/accounts/forms.py b/src/django-master/accounts/forms.py index 8578521..3ac3f11 100644 --- a/src/django-master/accounts/forms.py +++ b/src/django-master/accounts/forms.py @@ -35,8 +35,8 @@ from django.contrib.auth.forms import AuthenticationForm, UserCreationForm from django.core.exceptions import ValidationError from django.forms import widgets from django.utils.translation import gettext_lazy as _ -from . import utils # 导入自定义工具模块,可能用于验证码验证等功能 -from .models import BlogUser # 导入自定义用户模型 +from . import utils # jyn:导入自定义工具模块,可能用于验证码验证等功能 +from .models import BlogUser # jyn:导入自定义用户模型 class LoginForm(AuthenticationForm): @@ -45,15 +45,19 @@ class LoginForm(AuthenticationForm): 用于处理用户登录验证,主要扩展了表单字段的样式 """ def __init__(self, *args, **kwargs): - # 调用父类构造方法初始化表单 + # jyn:调用父类构造方法初始化表单 super(LoginForm, self).__init__(*args, **kwargs) - # 自定义用户名输入框:添加占位符和CSS类 + # jyn:自定义用户名输入框:添加占位符和CSS类 self.fields['username'].widget = widgets.TextInput( attrs={'placeholder': "username", "class": "form-control"}) +<<<<<<< HEAD # 自定义密码输入框:添加占位符和CSS类 >>>>>>> 8b27cdad9a9ccc84febce3bcf1d211ed109f96f2 +======= + # jyn:自定义密码输入框:添加占位符和CSS类 +>>>>>>> ef493f43496bf1ae99bf4389327ac0ae80bb9ae1 self.fields['password'].widget = widgets.PasswordInput( <<<<<<< HEAD attrs={'placeholder': "password", "class": "form-control"}) #为密码字段设置密码输入小部件,同样定义占位符和样式类。 @@ -86,13 +90,17 @@ class RegisterForm(UserCreationForm): >>>>>>> 8b27cdad9a9ccc84febce3bcf1d211ed109f96f2 >>>>>>> JYN_branch def __init__(self, *args, **kwargs): - # 调用父类构造方法初始化表单 + # jyn:调用父类构造方法初始化表单 super(RegisterForm, self).__init__(*args, **kwargs) <<<<<<< HEAD # 自定义用户名、邮箱和密码字段的HTML属性 ======= +<<<<<<< HEAD # 自定义各字段的输入控件,添加样式和占位符 +>>>>>>> JYN_branch +======= + # jyn:自定义各字段的输入控件,添加样式和占位符 >>>>>>> JYN_branch self.fields['username'].widget = widgets.TextInput( attrs={'placeholder': "username", "class": "form-control"}) @@ -117,14 +125,15 @@ class RegisterForm(UserCreationForm): 表单验证机制中,以clean_为前缀的方法会自动被调用 """ email = self.cleaned_data['email'] - # 检查该邮箱是否已存在于数据库中 + # jyn:检查该邮箱是否已存在于数据库中 if get_user_model().objects.filter(email=email).exists(): - raise ValidationError(_("email already exists")) # 抛出验证错误 + raise ValidationError(_("email already exists")) #jyn: 抛出验证错误 return email <<<<<<< HEAD <<<<<<< HEAD # 指定关联的用户模型和表单字段 class Meta: +<<<<<<< HEAD model = get_user_model() # 使用项目配置的用户模型(可能是自定义的BlogUser) fields = ("username", "email") # 注册表单中显示的字段 ======= @@ -141,6 +150,10 @@ class RegisterForm(UserCreationForm): fields = ("username", "email") #lxy Meta类指定关联模型为自定义用户模型,表单字段包含username和email >>>>>>> LXY_branch +======= + model = get_user_model() # jyn:使用项目配置的用户模型(可能是自定义的BlogUser) + fields = ("username", "email") # jyn:注册表单中显示的字段 +>>>>>>> JYN_branch # 忘记密码表单(验证邮箱和验证码) class ForgetPasswordForm(forms.Form): @@ -148,7 +161,7 @@ class ForgetPasswordForm(forms.Form): 忘记密码表单,用于用户重置密码的流程 包含新密码、确认密码、邮箱和验证码字段 """ - # 新密码字段 + # jyn:新密码字段 new_password1 = forms.CharField( label=_("New password"), widget=forms.PasswordInput( @@ -162,7 +175,11 @@ class ForgetPasswordForm(forms.Form): # 新密码字段2(用于确认) ======= +<<<<<<< HEAD # 确认新密码字段 +>>>>>>> JYN_branch +======= + # jyn:确认新密码字段 >>>>>>> JYN_branch new_password2 = forms.CharField( label="确认密码", @@ -177,7 +194,11 @@ class ForgetPasswordForm(forms.Form): # 邮箱字段 ======= +<<<<<<< HEAD # 邮箱字段(用于验证用户身份) +>>>>>>> JYN_branch +======= + # jyn:邮箱字段(用于验证用户身份) >>>>>>> JYN_branch email = forms.EmailField( label='邮箱', @@ -192,7 +213,11 @@ class ForgetPasswordForm(forms.Form): # 验证码字段 ======= +<<<<<<< HEAD # 验证码字段(用于身份验证) +>>>>>>> JYN_branch +======= + # jyn:验证码字段(用于身份验证) >>>>>>> JYN_branch code = forms.CharField( label=_('Code'), @@ -217,7 +242,7 @@ class ForgetPasswordForm(forms.Form): password1 = self.data.get("new_password1") password2 = self.data.get("new_password2") - # 检查两次密码是否一致 + # jyn:检查两次密码是否一致 if password1 and password2 and password1 != password2: raise ValidationError(_("passwords do not match")) <<<<<<< HEAD @@ -225,7 +250,7 @@ class ForgetPasswordForm(forms.Form): ======= - # 使用Django内置的密码验证器验证密码强度 + # jyn:使用Django内置的密码验证器验证密码强度 password_validation.validate_password(password2) >>>>>>> JYN_branch @@ -242,9 +267,9 @@ class ForgetPasswordForm(forms.Form): def clean_email(self): """验证邮箱是否已注册""" user_email = self.cleaned_data.get("email") - # 检查该邮箱是否存在于系统中 + # jyn:检查该邮箱是否存在于系统中 if not BlogUser.objects.filter(email=user_email).exists(): - # 提示邮箱不存在(实际应用中可能需要模糊提示以避免信息泄露) + # jyn:提示邮箱不存在(实际应用中可能需要模糊提示以避免信息泄露) raise ValidationError(_("email does not exist")) return user_email <<<<<<< HEAD @@ -260,17 +285,21 @@ class ForgetPasswordForm(forms.Form): def clean_code(self): """验证验证码是否有效""" code = self.cleaned_data.get("code") +<<<<<<< HEAD <<<<<<< HEAD error = utils.verify(# 调用工具函数验证验证码 ======= # 调用工具函数验证邮箱和验证码是否匹配 +======= + # jyn:调用工具函数验证邮箱和验证码是否匹配 +>>>>>>> JYN_branch error = utils.verify( >>>>>>> JYN_branch email=self.cleaned_data.get("email"), code=code, ) if error: - raise ValidationError(error) # 验证码无效时抛出错误 + raise ValidationError(error) # jyn:验证码无效时抛出错误 return code <<<<<<< HEAD <<<<<<< HEAD diff --git a/src/django-master/accounts/models.py b/src/django-master/accounts/models.py index 5529d12..7971f1d 100644 --- a/src/django-master/accounts/models.py +++ b/src/django-master/accounts/models.py @@ -3,7 +3,7 @@ from django.db import models from django.urls import reverse from django.utils.timezone import now from django.utils.translation import gettext_lazy as _ -from djangoblog.utils import get_current_site # 导入获取当前站点信息的工具函数 +from djangoblog.utils import get_current_site # jyn:导入获取当前站点信息的工具函数 # Create your models here. @@ -20,16 +20,20 @@ class BlogUser(AbstractUser): # 账号创建来源(如:网站注册/第三方登录等,可选) ======= """ - 自定义用户模型,继承自Django内置的AbstractUser + jyn:自定义用户模型,继承自Django内置的AbstractUser 扩展了默认用户模型的字段,以满足博客系统的特定需求 """ - # 昵称字段,允许为空 + # jyn:昵称字段,允许为空 nickname = models.CharField(_('nick name'), max_length=100, blank=True) - # 账号创建时间,默认为当前时间 + # jyn:账号创建时间,默认为当前时间 creation_time = models.DateTimeField(_('creation time'), default=now) - # 最后修改时间,默认为当前时间(通常需要在保存时更新) + # jyn:最后修改时间,默认为当前时间(通常需要在保存时更新) last_modify_time = models.DateTimeField(_('last modify time'), default=now) +<<<<<<< HEAD # 账号创建来源(如管理员添加、前台注册等),用于追踪用户注册渠道 +>>>>>>> JYN_branch +======= + # jyn:账号创建来源(如管理员添加、前台注册等),用于追踪用户注册渠道 >>>>>>> JYN_branch source = models.CharField(_('create source'), max_length=100, blank=True) # 获取用户详情页的绝对URL(用于模板中的{% url %}反向解析) @@ -45,7 +49,7 @@ class BlogUser(AbstractUser):#lxy自定义用户模型BlogUser,继承自Django >>>>>>> LXY_branch def get_absolute_url(self): """ - 返回用户详情页的URL + jyn:返回用户详情页的URL Django推荐为模型定义此方法,用于获取对象的标准URL """ return reverse( @@ -69,8 +73,12 @@ class BlogUser(AbstractUser):#lxy自定义用户模型BlogUser,继承自Django >>>>>>> JYN_branch def __str__(self): <<<<<<< HEAD +<<<<<<< HEAD <<<<<<< HEAD """模型的字符串表示,这里返回用户的邮箱""" +======= + """jyn:模型的字符串表示,这里返回用户的邮箱""" +>>>>>>> JYN_branch return self.email # 获取用户详情页的完整URL(包含域名,用于分享链接) ======= @@ -81,6 +89,7 @@ class BlogUser(AbstractUser):#lxy自定义用户模型BlogUser,继承自Django >>>>>>> LXY_branch def get_full_url(self): +<<<<<<< HEAD <<<<<<< HEAD site = get_current_site().domain# 获取当前站点域名 url = "https://{site}{path}".format(site=site, @@ -90,16 +99,21 @@ class BlogUser(AbstractUser):#lxy自定义用户模型BlogUser,继承自Django ======= """获取用户详情页的完整URL(包含域名)""" # 获取当前站点的域名 +======= + """jyn:获取用户详情页的完整URL(包含域名)""" + # jyn:获取当前站点的域名 +>>>>>>> JYN_branch site = get_current_site().domain - # 拼接完整URL(协议+域名+路径) + # jyn:拼接完整URL(协议+域名+路径) url = "https://{site}{path}".format( site=site, - path=self.get_absolute_url() # 调用get_absolute_url获取相对路径 + path=self.get_absolute_url() # jyn:调用get_absolute_url获取相对路径 ) >>>>>>> JYN_branch return url # 元数据配置(模型级别的选项) class Meta: +<<<<<<< HEAD <<<<<<< HEAD ordering = ['-id'] # 默认按ID降序排列 verbose_name = _('user') # 单数形式名称(后台显示) @@ -130,3 +144,10 @@ class BlogUser(AbstractUser):#lxy自定义用户模型BlogUser,继承自Django verbose_name_plural = verbose_name#lxy模型的复数显示名称与单数一致。 get_latest_by = 'id'#lxy指定按id获取最新记录 >>>>>>> LXY_branch +======= + """jyn:模型的元数据配置""" + ordering = ['-id'] # jyn:默认排序方式:按id降序(最新创建的用户在前) + verbose_name = _('user') # jyn:模型的单数显示名称(支持国际化) + verbose_name_plural = verbose_name # jyn:模型的复数显示名称(与单数相同) + get_latest_by = 'id' # jyn:指定使用id字段获取最新对象(用于Model.objects.latest()) +>>>>>>> JYN_branch diff --git a/src/django-master/accounts/tests.py b/src/django-master/accounts/tests.py index 47bffd0..7001dc8 100644 --- a/src/django-master/accounts/tests.py +++ b/src/django-master/accounts/tests.py @@ -3,10 +3,10 @@ from django.urls import reverse from django.utils import timezone from django.utils.translation import gettext_lazy as _ -from accounts.models import BlogUser # 导入自定义用户模型 -from blog.models import Article, Category # 导入博客相关模型 -from djangoblog.utils import * # 导入项目工具函数 -from . import utils # 导入当前应用的工具函数 +from accounts.models import BlogUser # jyn:导入自定义用户模型 +from blog.models import Article, Category # jyn:导入博客相关模型 +from djangoblog.utils import * # jyn:导入项目工具函数 +from . import utils # jyn:导入当前应用的工具函数 # Create your tests here. @@ -30,15 +30,22 @@ class AccountTest(TestCase): 测试前的初始化方法,会在每个测试方法执行前运行 用于创建测试所需的基础数据 """ +<<<<<<< HEAD self.client = Client() # 创建测试客户端,用于模拟用户请求 self.factory = RequestFactory() # 创建请求工厂,用于构建请求对象 # 创建一个测试用户 +>>>>>>> JYN_branch +======= + self.client = Client() # jyn:创建测试客户端,用于模拟用户请求 + self.factory = RequestFactory() # jyn:创建请求工厂,用于构建请求对象 + # jyn:创建一个测试用户 >>>>>>> JYN_branch self.blog_user = BlogUser.objects.create_user( username="test", email="admin@admin.com", password="12345678" ) +<<<<<<< HEAD <<<<<<< HEAD # 测试用的随机字符串 self.new_test = "xxx123--=" @@ -49,17 +56,25 @@ class AccountTest(TestCase): # 创建一个超级用户(用于测试管理员权限) ======= self.new_test = "xxx123--=" # 测试用的新密码 +======= + self.new_test = "xxx123--=" #jyn: 测试用的新密码 +>>>>>>> JYN_branch def test_validate_account(self): """测试用户账号验证相关功能,包括登录和管理员权限""" - site = get_current_site().domain # 获取当前站点域名 + site = get_current_site().domain # jyn:获取当前站点域名 +<<<<<<< HEAD # 创建一个超级用户 +>>>>>>> JYN_branch +======= + # jyn:创建一个超级用户 >>>>>>> JYN_branch user = BlogUser.objects.create_superuser( email="liangliangyy1@gmail.com", username="liangliangyy1", password="qwer!@#$ggg") +<<<<<<< HEAD <<<<<<< HEAD # 从数据库获取刚创建的超级用户(验证是否创建成功) testuser = BlogUser.objects.get(username='liangliangyy1') @@ -79,13 +94,27 @@ class AccountTest(TestCase): self.assertEqual(response.status_code, 200)# 验证返回200状态码 ======= self.assertEqual(loginresult, True) # 断言登录成功 +======= + # jyn:获取创建的用户 + testuser = BlogUser.objects.get(username='liangliangyy1') + + # jyn:测试登录功能 + loginresult = self.client.login( + username='liangliangyy1', + password='qwer!@#$ggg') + self.assertEqual(loginresult, True) #jyn: 断言登录成功 +>>>>>>> JYN_branch - # 测试访问管理员页面 + # jyn:测试访问管理员页面 response = self.client.get('/admin/') - self.assertEqual(response.status_code, 200) # 断言页面访问成功 + self.assertEqual(response.status_code, 200) # jyn:断言页面访问成功 +<<<<<<< HEAD >>>>>>> JYN_branch # 创建测试分类 +======= + # jyn:创建测试分类 +>>>>>>> JYN_branch category = Category() category.name = "categoryaaa" category.creation_time = timezone.now() @@ -94,8 +123,12 @@ class AccountTest(TestCase): <<<<<<< HEAD ======= +<<<<<<< HEAD >>>>>>> JYN_branch # 创建测试文章 +======= + # jyn:创建测试文章 +>>>>>>> JYN_branch article = Article() article.title = "nicetitleaaa" article.body = "nicecontentaaa" @@ -111,13 +144,14 @@ class AccountTest(TestCase): ======= article.author = user article.category = category - article.type = 'a' # 假设'a'表示文章类型 - article.status = 'p' # 假设'p'表示已发布 + article.type = 'a' # jyn:假设'a'表示文章类型 + article.status = 'p' # jyn:假设'p'表示已发布 article.save() - # 测试访问文章管理页面 + # jyn:测试访问文章管理页面 response = self.client.get(article.get_admin_url()) <<<<<<< HEAD +<<<<<<< HEAD <<<<<<< HEAD self.assertEqual(response.status_code, 200) # 断言页面访问成功 >>>>>>> JYN_branch @@ -127,6 +161,9 @@ class AccountTest(TestCase): ======= self.assertEqual(response.status_code, 200)#lxy测试管理员账号登录后台功能:创建超级用户,验证登录状态和后台页面访问状态 >>>>>>> LXY_branch +======= + self.assertEqual(response.status_code, 200) # jyn:断言页面访问成功 +>>>>>>> JYN_branch # 测试用户注册功能 def test_validate_register(self): @@ -134,7 +171,11 @@ class AccountTest(TestCase): # 验证测试邮箱初始不存在 ======= """测试用户注册功能,包括注册流程、邮箱验证和权限控制""" +<<<<<<< HEAD # 初始状态下,该邮箱应不存在 +>>>>>>> JYN_branch +======= + # jyn:初始状态下,该邮箱应不存在 >>>>>>> JYN_branch self.assertEquals( 0, len( @@ -144,7 +185,11 @@ class AccountTest(TestCase): # 模拟注册请求 ======= +<<<<<<< HEAD # 模拟用户注册提交 +>>>>>>> JYN_branch +======= + # jyn:模拟用户注册提交 >>>>>>> JYN_branch response = self.client.post(reverse('account:register'), { 'username': 'user1233', @@ -156,7 +201,11 @@ class AccountTest(TestCase): # 验证用户已创建(通过邮箱查询) ======= +<<<<<<< HEAD # 注册后,该邮箱应存在 +>>>>>>> JYN_branch +======= + #jyn: 注册后,该邮箱应存在 >>>>>>> JYN_branch self.assertEquals( 1, len( @@ -168,9 +217,13 @@ class AccountTest(TestCase): # 生成验证签名(用于邮箱验证等场景) ======= - # 获取刚注册的用户 + #jyn: 获取刚注册的用户 user = BlogUser.objects.filter(email='user123@user.com')[0] +<<<<<<< HEAD # 生成验证链接(模拟邮箱验证流程) +>>>>>>> JYN_branch +======= + # jyn:生成验证链接(模拟邮箱验证流程) >>>>>>> JYN_branch sign = get_sha256(get_sha256(settings.SECRET_KEY + str(user.id))) # 构造验证URL @@ -186,13 +239,17 @@ class AccountTest(TestCase): # 获取指定邮箱的用户并设置为超级用户和工作人员 ======= - # 访问验证链接 + # jyn:访问验证链接 response = self.client.get(url) - self.assertEqual(response.status_code, 200) # 断言验证页面访问成功 + self.assertEqual(response.status_code, 200) # jyn:断言验证页面访问成功 - # 登录新注册用户 + # jyn:登录新注册用户 self.client.login(username='user1233', password='password123!q@wE#R$T') +<<<<<<< HEAD # 提升用户权限 +>>>>>>> JYN_branch +======= + # jyn:提升用户权限 >>>>>>> JYN_branch user = BlogUser.objects.filter(email='user123@user.com')[0] user.is_superuser = True @@ -204,10 +261,14 @@ class AccountTest(TestCase): # 创建分类 ======= - # 清除缓存 + # jyn:清除缓存 delete_sidebar_cache() +<<<<<<< HEAD # 创建测试分类 +>>>>>>> JYN_branch +======= + # jyn:创建测试分类 >>>>>>> JYN_branch category = Category() category.name = "categoryaaa" @@ -218,7 +279,11 @@ class AccountTest(TestCase): # 创建文章 ======= +<<<<<<< HEAD # 创建测试文章 +>>>>>>> JYN_branch +======= + # jyn:创建测试文章 >>>>>>> JYN_branch article = Article() article.category = category @@ -241,19 +306,23 @@ class AccountTest(TestCase): # 测试使用错误密码登录 ======= - # 测试访问文章管理页面 + # jyn:测试访问文章管理页面 response = self.client.get(article.get_admin_url()) self.assertEqual(response.status_code, 200) - # 测试登出功能 + # jyn:测试登出功能 response = self.client.get(reverse('account:logout')) self.assertIn(response.status_code, [301, 302, 200]) # 登出通常是重定向 - # 登出后访问管理页面(应被拒绝或重定向) + # jyn:登出后访问管理页面(应被拒绝或重定向) response = self.client.get(article.get_admin_url()) self.assertIn(response.status_code, [301, 302, 200]) +<<<<<<< HEAD # 使用错误密码登录 +>>>>>>> JYN_branch +======= + # jyn:使用错误密码登录 >>>>>>> JYN_branch response = self.client.post(reverse('account:login'), { 'username': 'user1233', @@ -264,7 +333,11 @@ class AccountTest(TestCase): # 测试使用错误密码登录后访问文章管理URL(应重定向) ======= +<<<<<<< HEAD # 错误登录后访问管理页面 +>>>>>>> JYN_branch +======= + # jyn:错误登录后访问管理页面 >>>>>>> JYN_branch response = self.client.get(article.get_admin_url()) <<<<<<< HEAD @@ -281,6 +354,7 @@ class AccountTest(TestCase): def test_verify_email_code(self): """测试邮箱验证码验证功能""" to_email = "admin@admin.com" +<<<<<<< HEAD <<<<<<< HEAD code = generate_code() # 生成验证码 utils.set_code(to_email, code)# 存储验证码 @@ -304,20 +378,26 @@ class AccountTest(TestCase): ======= self.assertEqual(type(err), str)#lxy测试邮箱验证码功能:验证有效邮箱和无效邮箱的验证码校验结果 >>>>>>> LXY_branch +======= + code = generate_code() # jyn:生成验证码 + utils.set_code(to_email, code) # jyn:存储验证码 + utils.send_verify_email(to_email, code) # jyn:发送验证邮件 +>>>>>>> JYN_branch - # 验证正确的邮箱和验证码 + # jyn:验证正确的邮箱和验证码 err = utils.verify("admin@admin.com", code) - self.assertEqual(err, None) # 应无错误 + self.assertEqual(err, None) # jyn:应无错误 - # 验证错误的邮箱和正确的验证码 + # jyn:验证错误的邮箱和正确的验证码 err = utils.verify("admin@123.com", code) - self.assertEqual(type(err), str) # 应返回错误信息 + self.assertEqual(type(err), str) # jyn:应返回错误信息 >>>>>>> JYN_branch def test_forget_password_email_code_success(self): """测试发送密码重置验证码成功的情况""" resp = self.client.post( path=reverse("account:forget_password_code"), +<<<<<<< HEAD <<<<<<< HEAD data=dict(email="admin@admin.com") # 使用正确邮箱格式 ) @@ -345,11 +425,23 @@ class AccountTest(TestCase): def test_forget_password_email_code_fail(self): """测试发送密码重置验证码失败的情况""" # 不提供邮箱 +>>>>>>> JYN_branch +======= + data=dict(email="admin@admin.com") # jyn:使用已存在的邮箱 + ) + + self.assertEqual(resp.status_code, 200) # jyn:断言请求成功 + self.assertEqual(resp.content.decode("utf-8"), "ok") # jyn:断言返回成功信息 + + def test_forget_password_email_code_fail(self): + """测试发送密码重置验证码失败的情况""" + # jyn:不提供邮箱 >>>>>>> JYN_branch resp = self.client.post( path=reverse("account:forget_password_code"), data=dict() ) +<<<<<<< HEAD <<<<<<< HEAD self.assertEqual(resp.content.decode("utf-8"), "错误的邮箱") # 测试提供错误格式邮箱 @@ -357,11 +449,17 @@ class AccountTest(TestCase): self.assertEqual(resp.content.decode("utf-8"), "错误的邮箱") # 断言返回错误信息 # 提供无效格式的邮箱 +>>>>>>> JYN_branch +======= + self.assertEqual(resp.content.decode("utf-8"), "错误的邮箱") # jyn:断言返回错误信息 + + # jyn:提供无效格式的邮箱 >>>>>>> JYN_branch resp = self.client.post( path=reverse("account:forget_password_code"), data=dict(email="admin@com") ) +<<<<<<< HEAD <<<<<<< HEAD self.assertEqual(resp.content.decode("utf-8"), "错误的邮箱") # 测试忘记密码重置功能 - 成功情况 @@ -377,6 +475,15 @@ class AccountTest(TestCase): code = generate_code() # 生成验证码 utils.set_code(self.blog_user.email, code) # 存储验证码 # 准备重置密码的数据 +>>>>>>> JYN_branch +======= + self.assertEqual(resp.content.decode("utf-8"), "错误的邮箱") #jyn: 断言返回错误信息 + + def test_forget_password_email_success(self): + """测试密码重置成功的情况""" + code = generate_code() # jyn:生成验证码 + utils.set_code(self.blog_user.email, code) #jyn: 存储验证码 + # jyn:准备重置密码的数据 >>>>>>> JYN_branch data = dict( new_password1=self.new_test, # 新密码 @@ -384,27 +491,35 @@ class AccountTest(TestCase): email=self.blog_user.email,# 用户邮箱 code=code, # 验证码 ) +<<<<<<< HEAD <<<<<<< HEAD # 提交重置密码请求 ======= # 提交密码重置请求 +>>>>>>> JYN_branch +======= + # jyn:提交密码重置请求 >>>>>>> JYN_branch resp = self.client.post( path=reverse("account:forget_password"), data=data ) +<<<<<<< HEAD <<<<<<< HEAD self.assertEqual(resp.status_code, 302) # 应重定向 ======= self.assertEqual(resp.status_code, 302) # 成功重置后通常重定向 >>>>>>> JYN_branch +======= + self.assertEqual(resp.status_code, 302) # jyn:成功重置后通常重定向 +>>>>>>> JYN_branch - # 验证密码是否已更新 + # jyn:验证密码是否已更新 blog_user = BlogUser.objects.filter( email=self.blog_user.email, - ).first() # type: BlogUser - self.assertNotEqual(blog_user, None) # 断言用户存在 - # 断言密码修改成功 + ).first() # jyn:type: BlogUser + self.assertNotEqual(blog_user, None) # jyn:断言用户存在 + # jyn:断言密码修改成功 self.assertEqual(blog_user.check_password(data["new_password1"]), True) # 测试忘记密码重置功能 - 用户不存在情况 def test_forget_password_email_not_user(self): @@ -412,10 +527,14 @@ class AccountTest(TestCase): data = dict( new_password1=self.new_test, new_password2=self.new_test, +<<<<<<< HEAD <<<<<<< HEAD email="123@123.com",# 不存在的邮箱 ======= email="123@123.com", # 不存在的邮箱 +>>>>>>> JYN_branch +======= + email="123@123.com", # jyn:不存在的邮箱 >>>>>>> JYN_branch code="123456", ) @@ -424,11 +543,15 @@ class AccountTest(TestCase): data=data ) +<<<<<<< HEAD <<<<<<< HEAD self.assertEqual(resp.status_code, 200) # 应返回错误页面而非重定向 ======= self.assertEqual(resp.status_code, 200) # 应返回页面但不重置密码 >>>>>>> JYN_branch +======= + self.assertEqual(resp.status_code, 200) # jyn:应返回页面但不重置密码 +>>>>>>> JYN_branch # 测试忘记密码重置功能 - 验证码错误情况 def test_forget_password_email_code_error(self): @@ -438,18 +561,28 @@ class AccountTest(TestCase): # 使用错误验证码提交 ======= """测试使用错误的验证码重置密码的情况""" +<<<<<<< HEAD code = generate_code() # 生成正确验证码 utils.set_code(self.blog_user.email, code) # 存储验证码 # 使用错误的验证码 +>>>>>>> JYN_branch +======= + code = generate_code() # jyn:生成正确验证码 + utils.set_code(self.blog_user.email, code) #jyn: 存储验证码 + # jyn:使用错误的验证码 >>>>>>> JYN_branch data = dict( new_password1=self.new_test, new_password2=self.new_test, email=self.blog_user.email, +<<<<<<< HEAD <<<<<<< HEAD code="111111",# 错误验证码 ======= code="111111", # 错误的验证码 +>>>>>>> JYN_branch +======= + code="111111", # jyn:错误的验证码 >>>>>>> JYN_branch ) resp = self.client.post( @@ -459,6 +592,7 @@ class AccountTest(TestCase): <<<<<<< HEAD <<<<<<< HEAD +<<<<<<< HEAD <<<<<<< HEAD self.assertEqual(resp.status_code, 200)# 应返回错误页面而非重定向 ======= @@ -471,3 +605,6 @@ class AccountTest(TestCase): ======= self.assertEqual(resp.status_code, 200) # 应返回页面但不重置密码 >>>>>>> JYN_branch +======= + self.assertEqual(resp.status_code, 200) # jyn:应返回页面但不重置密码 +>>>>>>> JYN_branch diff --git a/src/django-master/accounts/urls.py b/src/django-master/accounts/urls.py index 3a0b0b3..81e18cd 100644 --- a/src/django-master/accounts/urls.py +++ b/src/django-master/accounts/urls.py @@ -38,53 +38,58 @@ urlpatterns = [ ] ======= from django.urls import path -from django.urls import re_path # 用于正则表达式匹配URL +from django.urls import re_path # jyn:用于正则表达式匹配URL -from . import views # 导入当前应用的视图函数/类 -from .forms import LoginForm # 导入自定义的登录表单 +from . import views # jyn:导入当前应用的视图函数/类 +from .forms import LoginForm # jyn:导入自定义的登录表单 -# 定义应用命名空间,避免URL名称冲突 +# jyn:定义应用命名空间,避免URL名称冲突 app_name = "accounts" +<<<<<<< HEAD <<<<<<< HEAD # URL路由配置列表,映射URL路径到对应的视图 +======= +# jyn:URL路由配置列表,映射URL路径到对应的视图 +>>>>>>> JYN_branch urlpatterns = [ - # 登录页面路由:使用正则匹配以login/结尾的路径 + # jyn:登录页面路由:使用正则匹配以login/结尾的路径 re_path(r'^login/$', - # 调用LoginView类视图,指定登录成功后重定向到首页(/) + # jyn:调用LoginView类视图,指定登录成功后重定向到首页(/) views.LoginView.as_view(success_url='/'), - name='login', # URL的名称,用于反向解析 - # 向视图传递额外参数:指定登录表单为自定义的LoginForm + name='login', # jyn:URL的名称,用于反向解析 + # jyn:向视图传递额外参数:指定登录表单为自定义的LoginForm kwargs={'authentication_form': LoginForm}), - # 注册页面路由:匹配以register/结尾的路径 + # jyn:注册页面路由:匹配以register/结尾的路径 re_path(r'^register/$', - # 调用RegisterView类视图,注册成功后重定向到首页 + # jyn:调用RegisterView类视图,注册成功后重定向到首页 views.RegisterView.as_view(success_url="/"), - name='register'), # URL名称,用于反向解析 + name='register'), # jyn:URL名称,用于反向解析 - # 登出功能路由:匹配以logout/结尾的路径 + # jyn:登出功能路由:匹配以logout/结尾的路径 re_path(r'^logout/$', - # 调用LogoutView类视图(Django内置或自定义) + # jyn:调用LogoutView类视图(Django内置或自定义) views.LogoutView.as_view(), - name='logout'), # URL名称 + name='logout'), #jyn: URL名称 - # 账号操作结果页面路由:精确匹配account/result.html路径 + # jyn:账号操作结果页面路由:精确匹配account/result.html路径 path(r'account/result.html', - # 调用函数视图account_result + # jyn:调用函数视图account_result views.account_result, - name='result'), # URL名称,用于展示注册/验证等结果 + name='result'), #jyn: URL名称,用于展示注册/验证等结果 - # 忘记密码页面路由:匹配以forget_password/结尾的路径 + # jyn:忘记密码页面路由:匹配以forget_password/结尾的路径 re_path(r'^forget_password/$', - # 调用ForgetPasswordView类视图 + # jyn:调用ForgetPasswordView类视图 views.ForgetPasswordView.as_view(), - name='forget_password'), # URL名称 + name='forget_password'), #jyn: URL名称 - # 发送密码重置验证码页面路由:匹配以forget_password_code/结尾的路径 + # jyn:发送密码重置验证码页面路由:匹配以forget_password_code/结尾的路径 re_path(r'^forget_password_code/$', - # 调用ForgetPasswordEmailCode类视图(处理发送验证码逻辑) + # jyn:调用ForgetPasswordEmailCode类视图(处理发送验证码逻辑) views.ForgetPasswordEmailCode.as_view(), +<<<<<<< HEAD name='forget_password_code'), # URL名称 ] >>>>>>> JYN_branch @@ -111,3 +116,7 @@ urlpatterns = [re_path(r'^login/$', name='forget_password_code'),#忘记密码验证码路由,对应ForgetPasswordEmailCode ] >>>>>>> LXY_branch +======= + name='forget_password_code'), # jyn:URL名称 +] +>>>>>>> JYN_branch diff --git a/src/django-master/accounts/user_login_backend.py b/src/django-master/accounts/user_login_backend.py index 283c8d9..6f85886 100644 --- a/src/django-master/accounts/user_login_backend.py +++ b/src/django-master/accounts/user_login_backend.py @@ -1,4 +1,5 @@ <<<<<<< HEAD +<<<<<<< HEAD # 导入 Django 认证系统所需的模块 from django.contrib.auth import get_user_model# 动态获取当前项目的 User 模型 from django.contrib.auth.backends import ModelBackend# Django 默认的认证后端基类 @@ -6,6 +7,10 @@ from django.contrib.auth.backends import ModelBackend# Django 默认的认证后 from django.contrib.auth import get_user_model # 获取项目配置的用户模型(支持自定义模型) from django.contrib.auth.backends import ModelBackend # 导入Django内置的模型认证后端 >>>>>>> JYN_branch +======= +from django.contrib.auth import get_user_model # jyn:获取项目配置的用户模型(支持自定义模型) +from django.contrib.auth.backends import ModelBackend # jyn:导入Django内置的模型认证后端 +>>>>>>> JYN_branch class EmailOrUsernameModelBackend(ModelBackend):#lxy自定义Django认证后端,支持用户名或邮箱两种方式登录。 @@ -47,11 +52,12 @@ class EmailOrUsernameModelBackend(ModelBackend):#lxy自定义Django认证后端 - password:前端传入的密码(明文) 返回:验证成功返回用户对象,失败返回None """ - # 判断输入的「username」是否包含@符号,以此区分邮箱和用户名 + # jyn:判断输入的「username」是否包含@符号,以此区分邮箱和用户名 if '@' in username: - # 若包含@,则按邮箱字段查询用户 + # jyn:若包含@,则按邮箱字段查询用户 kwargs = {'email': username} else: +<<<<<<< HEAD # 若不包含@,则按用户名字段查询用户 >>>>>>> JYN_branch kwargs = {'username': username} @@ -67,12 +73,23 @@ class EmailOrUsernameModelBackend(ModelBackend):#lxy自定义Django认证后端 # 用户不存在时返回 None(Django 会继续尝试其他认证后端) ======= # 根据上述条件从数据库查询唯一用户 +======= + # jyn:若不包含@,则按用户名字段查询用户 + kwargs = {'username': username} + + try: + # jyn:根据上述条件从数据库查询唯一用户 +>>>>>>> JYN_branch user = get_user_model().objects.get(**kwargs) - # 验证密码:check_password会自动将明文密码与数据库中存储的哈希密码比对 + # jyn:验证密码:check_password会自动将明文密码与数据库中存储的哈希密码比对 if user.check_password(password): - return user # 密码正确,返回用户对象(认证成功) + return user # jyn:密码正确,返回用户对象(认证成功) except get_user_model().DoesNotExist: +<<<<<<< HEAD # 若查询不到用户(用户名/邮箱不存在),返回None(认证失败) +>>>>>>> JYN_branch +======= + # jyn:若查询不到用户(用户名/邮箱不存在),返回None(认证失败) >>>>>>> JYN_branch return None #lxy核心认证逻辑:判断输入是否为邮箱(含@),分别用邮箱或用户名查询用户,验证密码后返回用户对象;若用户不存在则返回None。 @@ -102,9 +119,10 @@ class EmailOrUsernameModelBackend(ModelBackend):#lxy自定义Django认证后端 返回:存在则返回用户对象,不存在返回None """ try: - # 通过主键(ID)查询用户 + # jyn:通过主键(ID)查询用户 return get_user_model().objects.get(pk=username) except get_user_model().DoesNotExist: +<<<<<<< HEAD # 若用户不存在,返回None return None >>>>>>> JYN_branch @@ -114,3 +132,7 @@ class EmailOrUsernameModelBackend(ModelBackend):#lxy自定义Django认证后端 ======= #lxy根据用户ID(主键)查询用户,不存在则返回None,用于Django认证系统的用户查询环节 >>>>>>> LXY_branch +======= + # jyn:若用户不存在,返回None + return None +>>>>>>> JYN_branch diff --git a/src/django-master/accounts/utils.py b/src/django-master/accounts/utils.py index cc58cc5..4428b57 100644 --- a/src/django-master/accounts/utils.py +++ b/src/django-master/accounts/utils.py @@ -2,6 +2,7 @@ import typing # 用于类型注解 from datetime import timedelta # 用于处理时间间隔 +<<<<<<< HEAD <<<<<<< HEAD # 导入 Django 核心组件 from django.core.cache import cache # Django 缓存系统 @@ -22,6 +23,15 @@ from djangoblog.utils import send_email # 导入项目自定义的发送邮件 # 验证码有效期:5分钟(全局变量,统一控制时效) >>>>>>> JYN_branch +======= +from django.core.cache import cache # jyn:导入Django缓存模块,用于存储验证码 +from django.utils.translation import gettext # jyn:用于获取即时翻译文本 +from django.utils.translation import gettext_lazy as _ # jyn:用于延迟翻译文本(支持国际化) + +from djangoblog.utils import send_email #jyn: 导入项目自定义的发送邮件工具函数 + +# jyn:验证码有效期:5分钟(全局变量,统一控制时效) +>>>>>>> JYN_branch _code_ttl = timedelta(minutes=5) ======= _code_ttl = timedelta(minutes=5)#验证码有效期,设置为5分钟。 @@ -46,11 +56,15 @@ def send_verify_email(to_mail: str, code: str, subject: str = _("Verify Email")) code: 生成的随机验证码 subject: 邮件主题,默认值为“Verify Email”(支持国际化) """ - # 构造邮件HTML内容,包含验证码和有效期提示,使用%(code)s占位符注入验证码 + # jyn:构造邮件HTML内容,包含验证码和有效期提示,使用%(code)s占位符注入验证码 html_content = _( "You are resetting the password, the verification code is:%(code)s, valid within 5 minutes, please keep it " "properly") % {'code': code} +<<<<<<< HEAD # 调用发送邮件函数,参数依次为:收件人列表、邮件主题、邮件内容 +>>>>>>> JYN_branch +======= + # jyn:调用发送邮件函数,参数依次为:收件人列表、邮件主题、邮件内容 >>>>>>> JYN_branch send_email([to_mail], subject, html_content) @@ -75,11 +89,11 @@ def verify(email: str, code: str) -> typing.Optional[str]: 代码注释中指出当前错误处理逻辑不合理:应使用raise抛出异常,而非返回错误字符串 若返回错误字符串,调用方需额外判断返回值是否为错误,增加了代码耦合度 """ - # 从缓存中获取该邮箱对应的验证码 + # jyn:从缓存中获取该邮箱对应的验证码 cache_code = get_code(email) - # 对比用户输入的验证码与缓存中的验证码 + # jyn:对比用户输入的验证码与缓存中的验证码 if cache_code != code: - # 验证码不匹配时,返回国际化的错误提示 + #jyn: 验证码不匹配时,返回国际化的错误提示 return gettext("Verification code error") >>>>>>> JYN_branch @@ -104,7 +118,11 @@ def set_code(email: str, code: str): email: 作为缓存key的邮箱地址(确保一个邮箱对应一个验证码) code: 需要存入缓存的验证码 """ +<<<<<<< HEAD # 调用Django缓存的set方法:key=邮箱,value=验证码,timeout=有效期(秒) +>>>>>>> JYN_branch +======= + # jyn:调用Django缓存的set方法:key=邮箱,value=验证码,timeout=有效期(秒) >>>>>>> JYN_branch cache.set(email, code, _code_ttl.seconds) @@ -140,6 +158,11 @@ def get_code(email: str) -> typing.Optional[str]:#lxy从缓存中获取指定邮 Return: 缓存中存在该邮箱对应的验证码时返回字符串,不存在时返回None """ +<<<<<<< HEAD # 调用Django缓存的get方法,根据邮箱key获取验证码 return cache.get(email) >>>>>>> JYN_branch +======= + # jyn:调用Django缓存的get方法,根据邮箱key获取验证码 + return cache.get(email) +>>>>>>> JYN_branch diff --git a/src/django-master/accounts/views.py b/src/django-master/accounts/views.py index ef0e161..ac71db9 100644 --- a/src/django-master/accounts/views.py +++ b/src/django-master/accounts/views.py @@ -7,6 +7,7 @@ from django.conf import settings # Django 认证系统核心模块 from django.contrib import auth <<<<<<< HEAD +<<<<<<< HEAD # 认证相关常量(如重定向字段名) from django.contrib.auth import REDIRECT_FIELD_NAME # 获取当前用户模型的快捷方式 @@ -59,31 +60,47 @@ from django.contrib.auth import logout # 登出功能函数 from django.contrib.auth.forms import AuthenticationForm # Django内置登录表单 from django.contrib.auth.hashers import make_password # 密码哈希处理函数 from django.http import HttpResponseRedirect, HttpResponseForbidden # HTTP响应类 +======= +from django.contrib.auth import REDIRECT_FIELD_NAME # jyn:登录后重定向字段名常量 +from django.contrib.auth import get_user_model # jyn:获取项目配置的用户模型 +from django.contrib.auth import logout # jyn:登出功能函数 +from django.contrib.auth.forms import AuthenticationForm # jyn:Django内置登录表单 +from django.contrib.auth.hashers import make_password # jyn:密码哈希处理函数 +from django.http import HttpResponseRedirect, HttpResponseForbidden # jyn:HTTP响应类 +>>>>>>> JYN_branch from django.http.request import HttpRequest from django.http.response import HttpResponse -from django.shortcuts import get_object_or_404, render # 快捷函数 -from django.urls import reverse # URL反向解析 -from django.utils.decorators import method_decorator # 类视图装饰器工具 -from django.utils.http import url_has_allowed_host_and_scheme # 验证重定向URL安全性 -from django.views import View # 基础视图类 -from django.views.decorators.cache import never_cache # 禁止缓存装饰器 -from django.views.decorators.csrf import csrf_protect # CSRF保护装饰器 -from django.views.decorators.debug import sensitive_post_parameters # 敏感参数保护装饰器 -from django.views.generic import FormView, RedirectView # 通用类视图 +from django.shortcuts import get_object_or_404, render # jyn:快捷函数 +from django.urls import reverse # jyn:URL反向解析 +from django.utils.decorators import method_decorator # jyn:类视图装饰器工具 +from django.utils.http import url_has_allowed_host_and_scheme # jyn:验证重定向URL安全性 +from django.views import View # jyn:基础视图类 +from django.views.decorators.cache import never_cache # jyn:禁止缓存装饰器 +from django.views.decorators.csrf import csrf_protect #jyn: CSRF保护装饰器 +from django.views.decorators.debug import sensitive_post_parameters # jyn:敏感参数保护装饰器 +from django.views.generic import FormView, RedirectView # jyn:通用类视图 from djangoblog.utils import (send_email, get_sha256, get_current_site, - generate_code, delete_sidebar_cache) # 项目工具函数 -from . import utils # 当前应用工具函数(验证码相关) + generate_code, delete_sidebar_cache) #jyn: 项目工具函数 +from . import utils # jyn:当前应用工具函数(验证码相关) from .forms import (RegisterForm, LoginForm, ForgetPasswordForm, - ForgetPasswordCodeForm) # 当前应用表单类 -from .models import BlogUser # 自定义用户模型 + ForgetPasswordCodeForm) # jyn:当前应用表单类 +from .models import BlogUser # jyn:自定义用户模型 +<<<<<<< HEAD logger = logging.getLogger(__name__) # 初始化日志记录器 >>>>>>> JYN_branch # Create your views here. # 注册视图类(继承自 FormView,处理表单提交) +======= +logger = logging.getLogger(__name__) # jyn:初始化日志记录器 + + +# jyn:Create your views here. + +>>>>>>> JYN_branch class RegisterView(FormView): <<<<<<< HEAD # 指定使用的表单类 @@ -107,10 +124,10 @@ class RegisterView(FormView): 用户注册类视图,继承自FormView(处理表单提交的通用视图) 负责用户注册表单展示、数据验证、发送验证邮件及注册结果跳转 """ - form_class = RegisterForm # 指定使用的注册表单 - template_name = 'account/registration_form.html' # 注册页面模板路径 + form_class = RegisterForm # jyn:指定使用的注册表单 + template_name = 'account/registration_form.html' # jyn:注册页面模板路径 - @method_decorator(csrf_protect) # 为视图添加CSRF保护 + @method_decorator(csrf_protect) # jyn:为视图添加CSRF保护 def dispatch(self, *args, **kwargs): """重写分发方法,添加装饰器后调用父类逻辑""" >>>>>>> JYN_branch @@ -142,26 +159,30 @@ class RegisterView(FormView): ======= """表单验证通过后执行的逻辑(注册核心流程)""" if form.is_valid(): - # 1. 暂存用户数据,不立即保存(is_active设为False,需邮箱验证后激活) + # jyn:1. 暂存用户数据,不立即保存(is_active设为False,需邮箱验证后激活) user = form.save(False) - user.is_active = False # 初始状态:未激活(需邮箱验证) - user.source = 'Register' # 标记注册来源为“前台注册” - user.save(True) # 保存用户到数据库 + user.is_active = False # jyn:初始状态:未激活(需邮箱验证) + user.source = 'Register' # jyn:标记注册来源为“前台注册” + user.save(True) # jyn:保存用户到数据库 - # 2. 生成邮箱验证链接(包含签名,防止篡改) - site = get_current_site().domain # 获取当前站点域名 - # 双重SHA256加密:用SECRET_KEY+用户ID生成签名,确保链接安全性 + # jyn:2. 生成邮箱验证链接(包含签名,防止篡改) + site = get_current_site().domain # jyn:获取当前站点域名 + # jyn:双重SHA256加密:用SECRET_KEY+用户ID生成签名,确保链接安全性 sign = get_sha256(get_sha256(settings.SECRET_KEY + str(user.id))) - # 开发环境下替换域名(适配本地测试) + # jyn:开发环境下替换域名(适配本地测试) if settings.DEBUG: site = '127.0.0.1:8000' - # 反向解析结果页URL,拼接完整验证链接 + # jyn:反向解析结果页URL,拼接完整验证链接 path = reverse('account:result') url = "http://{site}{path}?type=validation&id={id}&sign={sign}".format( site=site, path=path, id=user.id, sign=sign) +<<<<<<< HEAD # 3. 构造验证邮件内容并发送 +>>>>>>> JYN_branch +======= + # jyn:3. 构造验证邮件内容并发送 >>>>>>> JYN_branch content = """

请点击下面链接验证您的邮箱

@@ -175,6 +196,7 @@ class RegisterView(FormView): """.format(url=url) # 发送验证邮件 send_email( +<<<<<<< HEAD <<<<<<< HEAD emailto=[ user.email, # 收件人列表 @@ -196,6 +218,11 @@ class RegisterView(FormView): emailto=[user.email], # 收件人邮箱(新注册用户的邮箱) title='验证您的电子邮箱', # 邮件标题 content=content # 邮件HTML内容 +======= + emailto=[user.email], # jyn:收件人邮箱(新注册用户的邮箱) + title='验证您的电子邮箱', #jyn: 邮件标题 + content=content #jyn: 邮件HTML内容 +>>>>>>> JYN_branch ) ======= })#form_valid方法中,保存用户并设置为非活跃状态,生成邮箱验证链接并发送验证邮件,最后重定向到结果页。 @@ -204,11 +231,11 @@ class RegisterView(FormView): })#lxyform_valid方法中,保存用户并设置为非活跃状态,生成邮箱验证链接并发送验证邮件,最后重定向到结果页。 >>>>>>> LXY_branch - # 4. 跳转到注册结果页(提示用户查收验证邮件) + # jyn:4. 跳转到注册结果页(提示用户查收验证邮件) url = reverse('accounts:result') + f'?type=register&id={str(user.id)}' return HttpResponseRedirect(url) else: - # 表单验证失败,重新渲染表单并显示错误 + # jyn:表单验证失败,重新渲染表单并显示错误 return self.render_to_response({'form': form}) >>>>>>> JYN_branch @@ -235,9 +262,9 @@ class LogoutView(RedirectView): 用户登出类视图,继承自RedirectView(处理重定向的通用视图) 负责清除用户会话、缓存,并重定向到登录页 """ - url = '/login/' # 登出后默认重定向地址(登录页) + url = '/login/' # jyn:登出后默认重定向地址(登录页) - @method_decorator(never_cache) # 禁止缓存登出页面,避免浏览器缓存导致的问题 + @method_decorator(never_cache) # jyn:禁止缓存登出页面,避免浏览器缓存导致的问题 def dispatch(self, request, *args, **kwargs): """重写分发方法,添加装饰器后调用父类逻辑""" >>>>>>> JYN_branch @@ -255,6 +282,7 @@ class LogoutView(RedirectView): return super(LogoutView, self).get(request, *args, **kwargs) ======= """处理GET请求(登出核心逻辑)""" +<<<<<<< HEAD logout(request) # 清除用户会话,实现登出 delete_sidebar_cache() # 删除侧边栏缓存(可能存储了用户相关信息) return super(LogoutView, self).get(request, *args, **kwargs) # 执行重定向 @@ -265,6 +293,11 @@ class LogoutView(RedirectView): ======= return super(LogoutView, self).get(request, *args, **kwargs)#lxyget方法中调用logout登出用户,删除侧边栏缓存后完成重定向 >>>>>>> LXY_branch +======= + logout(request) # jyn:清除用户会话,实现登出 + delete_sidebar_cache() # jyn:删除侧边栏缓存(可能存储了用户相关信息) + return super(LogoutView, self).get(request, *args, **kwargs) # jyn:执行重定向 +>>>>>>> JYN_branch # 登录视图,继承自FormView class LoginView(FormView): @@ -291,6 +324,7 @@ class LoginView(FormView): 用户登录类视图,继承自FormView 负责登录表单展示、数据验证、用户认证、记住登录状态及重定向 """ +<<<<<<< HEAD form_class = LoginForm # 指定使用的自定义登录表单 template_name = 'account/login.html' # 登录页面模板路径 success_url = '/' # 登录成功默认重定向地址(首页) @@ -299,9 +333,16 @@ class LoginView(FormView): ======= login_ttl = 2626560 #lxy 一个月的时间 >>>>>>> LXY_branch +======= + form_class = LoginForm #jyn: 指定使用的自定义登录表单 + template_name = 'account/login.html' # jyn:登录页面模板路径 + success_url = '/' # jyn:登录成功默认重定向地址(首页) + redirect_field_name = REDIRECT_FIELD_NAME # jyn:重定向字段名(默认next) + login_ttl = 2626560 #jyn: “记住登录”状态的有效期(秒),约等于1个月 +>>>>>>> JYN_branch - # 为视图添加多重装饰器:敏感参数保护、CSRF保护、禁止缓存 - @method_decorator(sensitive_post_parameters('password')) # 保护密码参数,避免日志泄露 + # jyn:为视图添加多重装饰器:敏感参数保护、CSRF保护、禁止缓存 + @method_decorator(sensitive_post_parameters('password')) # jyn:保护密码参数,避免日志泄露 @method_decorator(csrf_protect) @method_decorator(never_cache) def dispatch(self, request, *args, **kwargs): @@ -314,11 +355,16 @@ class LoginView(FormView): # 从GET参数中获取重定向URL ======= """添加额外上下文数据(重定向地址)到模板""" +<<<<<<< HEAD # 获取URL中的重定向参数(如登录前访问的受保护页面) +>>>>>>> JYN_branch +======= + # jyn:获取URL中的重定向参数(如登录前访问的受保护页面) >>>>>>> JYN_branch redirect_to = self.request.GET.get(self.redirect_field_name) # 如果不存在则设置为根路径 if redirect_to is None: +<<<<<<< HEAD <<<<<<< HEAD redirect_to = '/' # 将重定向URL添加到上下文 @@ -337,6 +383,10 @@ class LoginView(FormView): ======= redirect_to = '/' # 默认重定向到首页 kwargs['redirect_to'] = redirect_to # 将重定向地址传入模板上下文 +======= + redirect_to = '/' # jyn:默认重定向到首页 + kwargs['redirect_to'] = redirect_to # jyn:将重定向地址传入模板上下文 +>>>>>>> JYN_branch return super(LoginView, self).get_context_data(** kwargs) ======= @@ -344,11 +394,16 @@ class LoginView(FormView): >>>>>>> LXY_branch def form_valid(self, form): """表单验证通过后执行的逻辑(登录核心流程)""" +<<<<<<< HEAD # 用Django内置AuthenticationForm重新验证(确保认证逻辑符合默认规范) +>>>>>>> JYN_branch +======= + # jyn:用Django内置AuthenticationForm重新验证(确保认证逻辑符合默认规范) >>>>>>> JYN_branch form = AuthenticationForm(data=self.request.POST, request=self.request) # 再次验证表单 if form.is_valid(): +<<<<<<< HEAD <<<<<<< HEAD # 删除侧边栏缓存 delete_sidebar_cache() @@ -361,18 +416,30 @@ class LoginView(FormView): ======= delete_sidebar_cache() # 删除侧边栏缓存(更新用户登录状态) logger.info(self.redirect_field_name) # 日志记录重定向字段名 +======= + delete_sidebar_cache() # jyn:删除侧边栏缓存(更新用户登录状态) + logger.info(self.redirect_field_name) # jyn:日志记录重定向字段名 +>>>>>>> JYN_branch - # 执行登录:将用户信息存入会话 + # jyn:执行登录:将用户信息存入会话 auth.login(self.request, form.get_user()) +<<<<<<< HEAD # 处理“记住我”功能:若勾选,设置会话有效期为1个月 +>>>>>>> JYN_branch +======= + # jyn:处理“记住我”功能:若勾选,设置会话有效期为1个月 >>>>>>> JYN_branch if self.request.POST.get("remember"): # 设置较长的会话过期时间 self.request.session.set_expiry(self.login_ttl) +<<<<<<< HEAD <<<<<<< HEAD # 调用父类方法处理成功跳转 ======= # 调用父类form_valid,执行重定向 +>>>>>>> JYN_branch +======= + # jyn:调用父类form_valid,执行重定向 >>>>>>> JYN_branch return super(LoginView, self).form_valid(form) <<<<<<< HEAD @@ -380,6 +447,7 @@ class LoginView(FormView): #lxyreturn HttpResponseRedirect('/') >>>>>>> LXY_branch else: +<<<<<<< HEAD <<<<<<< HEAD # 表单无效,重新渲染表单并显示错误 return self.render_to_response({ @@ -409,16 +477,23 @@ class LoginView(FormView): <<<<<<< HEAD ======= # 表单验证失败(如密码错误),重新渲染表单并显示错误 +======= + # jyn:表单验证失败(如密码错误),重新渲染表单并显示错误 +>>>>>>> JYN_branch return self.render_to_response({'form': form}) def get_success_url(self): """自定义登录成功后的重定向地址(优先使用URL中的next参数)""" - # 获取POST请求中的重定向地址(用户登录前尝试访问的页面) + # jyn:获取POST请求中的重定向地址(用户登录前尝试访问的页面) redirect_to = self.request.POST.get(self.redirect_field_name) - # 验证重定向地址的安全性:避免跳转到外部恶意网站 + # jyn:验证重定向地址的安全性:避免跳转到外部恶意网站 if not url_has_allowed_host_and_scheme( url=redirect_to, allowed_hosts=[self.request.get_host()]): +<<<<<<< HEAD redirect_to = self.success_url # 不安全则使用默认重定向地址 +>>>>>>> JYN_branch +======= + redirect_to = self.success_url # jyn:不安全则使用默认重定向地址 >>>>>>> JYN_branch return redirect_to ======= @@ -446,16 +521,17 @@ def account_result(request): 账号操作结果视图函数(函数视图) 处理注册成功提示、邮箱验证逻辑,并展示结果页面 """ - # 从URL参数中获取操作类型(register/validation)和用户ID + # jyn:从URL参数中获取操作类型(register/validation)和用户ID type = request.GET.get('type') id = request.GET.get('id') - # 获取对应的用户,若不存在则返回404 + # jyn:获取对应的用户,若不存在则返回404 user = get_object_or_404(get_user_model(), id=id) <<<<<<< HEAD <<<<<<< HEAD logger.info(type) # 日志记录操作类型 +<<<<<<< HEAD # 若用户已激活,直接重定向到首页(避免重复验证) ======= logger.info(type)#处理注册和邮箱验证的结果逻辑,根据type参数区分场景: @@ -467,26 +543,39 @@ def account_result(request): return HttpResponseRedirect('/') # 处理合法的操作类型(注册成功提示/邮箱验证) +>>>>>>> JYN_branch +======= + # jyn:若用户已激活,直接重定向到首页(避免重复验证) + if user.is_active: + return HttpResponseRedirect('/') + + # jyn:处理合法的操作类型(注册成功提示/邮箱验证) >>>>>>> JYN_branch if type and type in ['register', 'validation']: if type == 'register': - # 注册成功:提示用户查收验证邮件 + # jyn:注册成功:提示用户查收验证邮件 content = ''' 恭喜您注册成功,一封验证邮件已经发送到您的邮箱,请验证您的邮箱后登录本站。 ''' title = '注册成功' else: +<<<<<<< HEAD <<<<<<< HEAD # 生成验证签名 ======= # 邮箱验证:验证签名是否正确,正确则激活用户 # 重新计算签名,与URL中的签名对比(防止链接篡改) +>>>>>>> JYN_branch +======= + # jyn:邮箱验证:验证签名是否正确,正确则激活用户 + # jyn:重新计算签名,与URL中的签名对比(防止链接篡改) >>>>>>> JYN_branch c_sign = get_sha256(get_sha256(settings.SECRET_KEY + str(user.id))) # 获取请求中的签名 sign = request.GET.get('sign') # 验证签名是否匹配 if sign != c_sign: +<<<<<<< HEAD <<<<<<< HEAD return HttpResponseForbidden() # 激活用户账户 @@ -499,25 +588,40 @@ def account_result(request): user.is_active = True user.save() # 验证成功:提示用户可登录 +>>>>>>> JYN_branch +======= + return HttpResponseForbidden() # jyn:签名不匹配,返回403禁止访问 + # jyn:激活用户:将is_active设为True + user.is_active = True + user.save() + # jyn:验证成功:提示用户可登录 >>>>>>> JYN_branch content = ''' 恭喜您已经成功的完成邮箱验证,您现在可以使用您的账号来登录本站。 ''' title = '验证成功' +<<<<<<< HEAD <<<<<<< HEAD # 渲染结果页面 ======= # 渲染结果页面,传递标题和内容 +>>>>>>> JYN_branch +======= + # jyn:渲染结果页面,传递标题和内容 >>>>>>> JYN_branch return render(request, 'account/result.html', { 'title': title, 'content': content }) else: +<<<<<<< HEAD <<<<<<< HEAD # 无效类型重定向到首页 ======= # 操作类型不合法,重定向到首页 +>>>>>>> JYN_branch +======= + # jyn:操作类型不合法,重定向到首页 >>>>>>> JYN_branch return HttpResponseRedirect('/') @@ -535,6 +639,7 @@ class ForgetPasswordView(FormView): 忘记密码类视图,继承自FormView 负责密码重置表单展示、数据验证,及更新用户密码 """ +<<<<<<< HEAD form_class = ForgetPasswordForm # 指定使用的密码重置表单 template_name = 'account/forget_password.html' # 密码重置页面模板路径 >>>>>>> JYN_branch @@ -544,12 +649,17 @@ class ForgetPasswordView(FormView): ======= template_name = 'account/forget_password.html'#lxy处理忘记密码逻辑,指定表单类ForgetPasswordForm和模板account/forget_password.html >>>>>>> LXY_branch +======= + form_class = ForgetPasswordForm # jyn:指定使用的密码重置表单 + template_name = 'account/forget_password.html' # jyn:密码重置页面模板路径 +>>>>>>> JYN_branch # 表单验证通过后的处理 def form_valid(self, form): """表单验证通过后执行的逻辑(密码重置核心流程)""" if form.is_valid(): +<<<<<<< HEAD <<<<<<< HEAD # 根据邮箱获取用户对象 blog_user = BlogUser.objects.filter(email=form.cleaned_data.get("email")).get() @@ -560,10 +670,18 @@ class ForgetPasswordView(FormView): email=form.cleaned_data.get("email") ).get() # 2. 对新密码进行哈希处理,并更新用户密码 +>>>>>>> JYN_branch +======= + # jyn:1. 获取表单中的邮箱,查询对应的用户 + blog_user = BlogUser.objects.filter( + email=form.cleaned_data.get("email") + ).get() + # jyn:2. 对新密码进行哈希处理,并更新用户密码 >>>>>>> JYN_branch blog_user.password = make_password(form.cleaned_data["new_password2"]) # 保存用户对象 blog_user.save() +<<<<<<< HEAD <<<<<<< HEAD # 重定向到登录页面 return HttpResponseRedirect('/login/') @@ -576,6 +694,12 @@ class ForgetPasswordView(FormView): return HttpResponseRedirect('/login/') else: # 表单验证失败(如验证码错误、密码不一致),重新渲染表单 +>>>>>>> JYN_branch +======= + # jyn:3. 密码重置成功,重定向到登录页 + return HttpResponseRedirect('/login/') + else: + # jyn:表单验证失败(如验证码错误、密码不一致),重新渲染表单 >>>>>>> JYN_branch return self.render_to_response({'form': form}) @@ -617,17 +741,18 @@ class ForgetPasswordEmailCode(View):#lxy处理忘记密码的邮箱验证码发 """ def post(self, request: HttpRequest): """处理POST请求(发送验证码核心逻辑)""" - # 1. 验证邮箱表单数据 + #jyn: 1. 验证邮箱表单数据 form = ForgetPasswordCodeForm(request.POST) if not form.is_valid(): - return HttpResponse("错误的邮箱") # 邮箱格式不合法,返回错误提示 + return HttpResponse("错误的邮箱") # jyn:邮箱格式不合法,返回错误提示 - # 2. 生成验证码并发送邮件 - to_email = form.cleaned_data["email"] # 获取合法的邮箱地址 - code = generate_code() # 生成随机验证码 - utils.send_verify_email(to_email, code) # 发送验证码邮件 - utils.set_code(to_email, code) # 将验证码存入缓存(设置有效期) + # jyn:2. 生成验证码并发送邮件 + to_email = form.cleaned_data["email"] # jyn:获取合法的邮箱地址 + code = generate_code() # jyn:生成随机验证码 + utils.send_verify_email(to_email, code) # jyn:发送验证码邮件 + utils.set_code(to_email, code) # jyn:将验证码存入缓存(设置有效期) +<<<<<<< HEAD # 3. 操作成功,返回“ok”提示 return HttpResponse("ok") >>>>>>> JYN_branch @@ -639,3 +764,7 @@ class ForgetPasswordEmailCode(View):#lxy处理忘记密码的邮箱验证码发 ======= return HttpResponse("ok")#lxypost方法中验证邮箱表单,生成并发送验证码,将验证码存入缓存后返回成功标识 >>>>>>> LXY_branch +======= + # jyn:3. 操作成功,返回“ok”提示 + return HttpResponse("ok") +>>>>>>> JYN_branch