diff --git a/src/DjangoBlog-master(1)/DjangoBlog-master/blog/context_processors.py b/src/DjangoBlog-master(1)/DjangoBlog-master/blog/context_processors.py
index f970a70..cc2a5dc 100644
--- a/src/DjangoBlog-master(1)/DjangoBlog-master/blog/context_processors.py
+++ b/src/DjangoBlog-master(1)/DjangoBlog-master/blog/context_processors.py
@@ -1,88 +1,44 @@
-# 导入日志模块,用于记录系统运行时的信息和错误
import logging
-# 导入Django的时间工具,用于获取当前时间
from django.utils import timezone
-# 导入自定义工具:缓存工具和获取博客设置的方法
from djangoblog.utils import cache, get_blog_setting
-# 导入当前应用的模型:分类和文章模型
from .models import Category, Article
-# 创建日志记录器,用于记录当前模块的日志信息
logger = logging.getLogger(__name__)
def seo_processor(requests):
- """
- 自定义上下文处理器:用于在所有模板中全局共享SEO相关的配置和数据
- 上下文处理器会在每次请求时被调用,返回的字典会自动注入到所有模板中
-
- Args:
- requests: HttpRequest对象,包含当前请求的信息(如协议、主机等)
-
- Returns:
- dict: 包含网站配置、导航数据等的字典,供模板全局使用
- """
- # 定义缓存键,用于标识当前处理器的缓存数据
key = 'seo_processor'
- # 尝试从缓存中获取数据,减少数据库查询和计算开销
value = cache.get(key)
-
- # 如果缓存中存在数据,直接返回缓存内容
if value:
return value
else:
- # 缓存未命中时,记录日志并重新计算数据
logger.info('set processor cache.')
- # 获取博客的全局设置(从数据库或其他配置源)
setting = get_blog_setting()
-
- # 构建需要返回给模板的数据集
value = {
- # 网站名称(用于页面标题等)
'SITE_NAME': setting.site_name,
- # 是否显示谷歌广告
'SHOW_GOOGLE_ADSENSE': setting.show_google_adsense,
- # 谷歌广告代码
'GOOGLE_ADSENSE_CODES': setting.google_adsense_codes,
- # 网站SEO描述(用于meta标签)
'SITE_SEO_DESCRIPTION': setting.site_seo_description,
- # 网站描述(用于页面展示)
'SITE_DESCRIPTION': setting.site_description,
- # 网站关键词(用于meta标签,提升SEO)
'SITE_KEYWORDS': setting.site_keywords,
- # 网站基础URL(协议+域名,如https://example.com/)
'SITE_BASE_URL': requests.scheme + '://' + requests.get_host() + '/',
- # 文章摘要长度(用于列表页显示)
'ARTICLE_SUB_LENGTH': setting.article_sub_length,
- # 导航栏显示的分类列表(从数据库查询所有分类)
'nav_category_list': Category.objects.all(),
- # 导航栏显示的页面列表(筛选类型为"页面"且状态为"已发布"的文章)
'nav_pages': Article.objects.filter(
- type='p', # 'p'表示页面(page),区别于普通文章(article)
- status='p'), # 'p'表示已发布(published)
- # 是否开启网站评论功能
+ type='p',
+ status='p'),
'OPEN_SITE_COMMENT': setting.open_site_comment,
- # 网站备案号
'BEIAN_CODE': setting.beian_code,
- # 网站统计代码(如百度统计、Google Analytics)
'ANALYTICS_CODE': setting.analytics_code,
- # 公安备案号
"BEIAN_CODE_GONGAN": setting.gongan_beiancode,
- # 是否显示公安备案号
"SHOW_GONGAN_CODE": setting.show_gongan_code,
- # 当前年份(用于页脚版权信息等)
"CURRENT_YEAR": timezone.now().year,
- # 全局页头代码(如自定义CSS、JS)
"GLOBAL_HEADER": setting.global_header,
- # 全局页脚代码
"GLOBAL_FOOTER": setting.global_footer,
- # 评论是否需要审核后才显示
"COMMENT_NEED_REVIEW": setting.comment_need_review,
}
-
- # 将数据存入缓存,有效期为10小时(60秒*60分*10小时)
- # 减少重复计算和数据库查询,提升性能
cache.set(key, value, 60 * 60 * 10)
return value
+
diff --git a/src/DjangoBlog-master(1)/DjangoBlog-master/comments/admin.py b/src/DjangoBlog-master(1)/DjangoBlog-master/comments/admin.py
index 481b21b..a814f3f 100644
--- a/src/DjangoBlog-master(1)/DjangoBlog-master/comments/admin.py
+++ b/src/DjangoBlog-master(1)/DjangoBlog-master/comments/admin.py
@@ -6,40 +6,29 @@ from django.utils.translation import gettext_lazy as _
def disable_commentstatus(modeladmin, request, queryset):
queryset.update(is_enable=False)
- # 批量禁用评论:将选中评论的is_enable字段设为False
+
def enable_commentstatus(modeladmin, request, queryset):
queryset.update(is_enable=True)
- # 批量启用评论:将选中评论的is_enable字段设为True
+
disable_commentstatus.short_description = _('Disable comments')
enable_commentstatus.short_description = _('Enable comments')
-# 设置动作在后台下拉菜单中的显示名称
+
class CommentAdmin(admin.ModelAdmin):
list_per_page = 20
- # 每页显示20条评论
-
list_display = (
'id',
'body',
- 'link_to_userinfo', # 自定义方法显示用户信息链接
- 'link_to_article', # 自定义方法显示文章链接
+ 'link_to_userinfo',
+ 'link_to_article',
'is_enable',
'creation_time')
- # 列表页面显示的字段
-
list_display_links = ('id', 'body', 'is_enable')
- # 这些字段可以作为链接点击进入编辑页面
-
list_filter = ('is_enable',)
- # 右侧过滤器:按启用状态筛选
-
exclude = ('creation_time', 'last_modify_time')
- # 编辑页面中排除这些字段(自动生成的时间戳)
-
actions = [disable_commentstatus, enable_commentstatus]
- # 注册可用的批量动作
def link_to_userinfo(self, obj):
info = (obj.author._meta.app_label, obj.author._meta.model_name)
@@ -47,15 +36,12 @@ class CommentAdmin(admin.ModelAdmin):
return format_html(
u'%s' %
(link, obj.author.nickname if obj.author.nickname else obj.author.email))
- # 生成指向用户编辑页面的链接,显示昵称(如果没有则显示邮箱)
def link_to_article(self, obj):
info = (obj.article._meta.app_label, obj.article._meta.model_name)
link = reverse('admin:%s_%s_change' % info, args=(obj.article.id,))
return format_html(
u'%s' % (link, obj.article.title))
- # 生成指向文章编辑页面的链接,显示文章标题
link_to_userinfo.short_description = _('User')
link_to_article.short_description = _('Article')
- # 设置自定义方法在列表中的列标题
\ No newline at end of file
diff --git a/src/DjangoBlog-master(1)/DjangoBlog-master/comments/models.py b/src/DjangoBlog-master(1)/DjangoBlog-master/comments/models.py
index d7235ce..0d052b1 100644
--- a/src/DjangoBlog-master(1)/DjangoBlog-master/comments/models.py
+++ b/src/DjangoBlog-master(1)/DjangoBlog-master/comments/models.py
@@ -9,63 +9,31 @@ from blog.models import Article
# Create your models here.
class Comment(models.Model):
- """
- 评论模型类
- 用于存储博客文章的评论信息,支持多级回复功能
- """
-
- # 评论正文,最大长度300字符,在管理界面显示为'正文'
body = models.TextField('正文', max_length=300)
-
- # 评论创建时间,默认值为当前时间,使用Django的国际化支持
creation_time = models.DateTimeField(_('creation time'), default=now)
-
- # 评论最后修改时间,默认值为当前时间
last_modify_time = models.DateTimeField(_('last modify time'), default=now)
-
- # 评论作者,关联用户模型,删除用户时级联删除其所有评论
author = models.ForeignKey(
settings.AUTH_USER_MODEL,
verbose_name=_('author'),
on_delete=models.CASCADE)
-
- # 所属文章,关联文章模型,删除文章时级联删除所有相关评论
article = models.ForeignKey(
Article,
verbose_name=_('article'),
on_delete=models.CASCADE)
-
- # 父级评论,支持评论回复功能,允许为空表示顶级评论
parent_comment = models.ForeignKey(
- 'self', # 自关联,指向同一个模型
+ 'self',
verbose_name=_('parent comment'),
- blank=True, # 在表单中允许为空
- null=True, # 在数据库中允许为NULL
- on_delete=models.CASCADE) # 删除父评论时级联删除子评论
-
- # 评论是否启用(审核通过),默认未启用,不允许为空
+ blank=True,
+ null=True,
+ on_delete=models.CASCADE)
is_enable = models.BooleanField(_('enable'),
default=False, blank=False, null=False)
class Meta:
- """
- 模型的元数据配置
- """
- # 按ID降序排列,新的评论显示在前面
ordering = ['-id']
-
- # 单数名称,在管理界面显示
verbose_name = _('comment')
-
- # 复数名称,与单数相同
verbose_name_plural = verbose_name
-
- # 指定获取最新记录时使用的字段
get_latest_by = 'id'
def __str__(self):
- """
- 对象的字符串表示方法
- 在Django管理界面和其他显示对象的地方使用
- """
- return self.body # 直接返回评论正文作为显示内容
\ No newline at end of file
+ return self.body
\ No newline at end of file
diff --git a/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/admin.py b/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/admin.py
index 9ec5080..d3ffcd6 100644
--- a/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/admin.py
+++ b/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/admin.py
@@ -37,7 +37,7 @@ class OAuthUserAdmin(admin.ModelAdmin):
# 右侧筛选器配置
list_filter = ('author', 'type',)
- # 只读字段列表(初始为空)
+ # 只读字段列表,开始为空
readonly_fields = []
def get_readonly_fields(self, request, obj=None):
diff --git a/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/apps.py b/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/apps.py
index 12d7409..42788ab 100644
--- a/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/apps.py
+++ b/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/apps.py
@@ -11,5 +11,5 @@ class OauthConfig(AppConfig):
"""
# 指定应用的Python路径,Django使用这个名称来识别应用
- # 这应该与应用目录的名称保持一致
+ # 这应该与应用目录的名称保持相同
name = 'oauth'
\ No newline at end of file
diff --git a/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/forms.py b/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/forms.py
index b7c9bf4..0db6327 100644
--- a/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/forms.py
+++ b/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/forms.py
@@ -9,7 +9,7 @@ class RequireEmailForm(forms.Form):
通常在第三方OAuth服务没有返回邮箱信息时使用
"""
- # 邮箱字段,标签显示为'电子邮箱',必填字段
+ # 邮箱字段,标签显示为'电子邮箱'
email = forms.EmailField(label='电子邮箱', required=True)
# OAuth用户ID隐藏字段,用于关联OAuth用户记录
diff --git a/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/models.py b/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/models.py
index f9fe8be..b4b570d 100644
--- a/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/models.py
+++ b/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/models.py
@@ -12,7 +12,7 @@ class OAuthUser(models.Model):
用于存储通过第三方OAuth服务登录的用户信息
"""
- # 关联到系统的本地用户,允许为空(初次OAuth登录时可能还未关联)
+ # 关联到系统的本地用户,允许为空
author = models.ForeignKey(
settings.AUTH_USER_MODEL,
verbose_name=_('author'),
diff --git a/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/tests.py b/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/tests.py
index bb23b9b..8198f84 100644
--- a/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/tests.py
+++ b/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/tests.py
@@ -13,43 +13,81 @@ from oauth.oauthmanager import BaseOauthManager
# Create your tests here.
class OAuthConfigTest(TestCase):
+ """
+ OAuth配置基础测试类
+ 测试OAuth登录流程的基本功能
+ """
+
def setUp(self):
- self.client = Client()
- self.factory = RequestFactory()
+ """
+ 测试初始化方法,在每个测试方法执行前运行
+ """
+ self.client = Client() # Django测试客户端,用于模拟HTTP请求
+ self.factory = RequestFactory() # 用于创建请求对象的工厂
def test_oauth_login_test(self):
+ """
+ 测试OAuth登录流程
+ 验证微博OAuth登录的跳转和授权流程
+ """
+ # 创建微博OAuth配置
c = OAuthConfig()
c.type = 'weibo'
c.appkey = 'appkey'
c.appsecret = 'appsecret'
c.save()
+ # 测试OAuth登录请求,应该重定向到微博授权页面
response = self.client.get('/oauth/oauthlogin?type=weibo')
- self.assertEqual(response.status_code, 302)
- self.assertTrue("api.weibo.com" in response.url)
+ self.assertEqual(response.status_code, 302) # 验证重定向状态码
+ self.assertTrue("api.weibo.com" in response.url) # 验证跳转到微博授权页面
+ # 测试授权回调处理,应该重定向到首页
response = self.client.get('/oauth/authorize?type=weibo&code=code')
- self.assertEqual(response.status_code, 302)
- self.assertEqual(response.url, '/')
+ self.assertEqual(response.status_code, 302) # 验证重定向状态码
+ self.assertEqual(response.url, '/') # 验证跳转到首页
class OauthLoginTest(TestCase):
+ """
+ OAuth登录详细测试类
+ 测试各种OAuth服务提供商的登录流程
+ """
+
def setUp(self) -> None:
- self.client = Client()
- self.factory = RequestFactory()
- self.apps = self.init_apps()
+ """
+ 测试初始化方法
+ """
+ self.client = Client() # Django测试客户端
+ self.factory = RequestFactory() # 请求工厂
+ self.apps = self.init_apps() # 初始化所有OAuth应用配置
def init_apps(self):
+ """
+ 初始化所有支持的OAuth应用配置
+ 为每种OAuth服务创建测试配置
+ """
+ # 获取所有OAuth管理器的子类实例
applications = [p() for p in BaseOauthManager.__subclasses__()]
for application in applications:
+ # 为每个OAuth服务创建配置
c = OAuthConfig()
- c.type = application.ICON_NAME.lower()
- c.appkey = 'appkey'
- c.appsecret = 'appsecret'
+ c.type = application.ICON_NAME.lower() # 服务类型(小写)
+ c.appkey = 'appkey' # 测试用的AppKey
+ c.appsecret = 'appsecret' # 测试用的AppSecret
c.save()
return applications
def get_app_by_type(self, type):
+ """
+ 根据类型获取对应的OAuth应用实例
+
+ Args:
+ type: OAuth服务类型
+
+ Returns:
+ 对应的OAuth管理器实例
+ """
for app in self.apps:
if app.ICON_NAME.lower() == type:
return app
@@ -57,73 +95,117 @@ class OauthLoginTest(TestCase):
@patch("oauth.oauthmanager.WBOauthManager.do_post")
@patch("oauth.oauthmanager.WBOauthManager.do_get")
def test_weibo_login(self, mock_do_get, mock_do_post):
+ """
+ 测试微博OAuth登录流程
+ 使用mock模拟API调用
+ """
weibo_app = self.get_app_by_type('weibo')
- assert weibo_app
+ assert weibo_app # 确保获取到微博应用实例
+
+ # 获取授权URL
url = weibo_app.get_authorization_url()
+
+ # 设置mock返回值 - 获取access token
mock_do_post.return_value = json.dumps({"access_token": "access_token",
"uid": "uid"
})
+ # 设置mock返回值 - 获取用户信息
mock_do_get.return_value = json.dumps({
"avatar_large": "avatar_large",
"screen_name": "screen_name",
"id": "id",
"email": "email",
})
+
+ # 执行获取access token的操作
userinfo = weibo_app.get_access_token_by_code('code')
+
+ # 验证返回的用户信息
self.assertEqual(userinfo.token, 'access_token')
self.assertEqual(userinfo.openid, 'id')
@patch("oauth.oauthmanager.GoogleOauthManager.do_post")
@patch("oauth.oauthmanager.GoogleOauthManager.do_get")
def test_google_login(self, mock_do_get, mock_do_post):
+ """
+ 测试Google OAuth登录流程
+ """
google_app = self.get_app_by_type('google')
assert google_app
+
url = google_app.get_authorization_url()
+
+ # 模拟Google OAuth的token响应
mock_do_post.return_value = json.dumps({
"access_token": "access_token",
"id_token": "id_token",
})
+
+ # 模拟Google用户信息响应
mock_do_get.return_value = json.dumps({
"picture": "picture",
"name": "name",
- "sub": "sub",
+ "sub": "sub", # Google的用户ID字段
"email": "email",
})
+
token = google_app.get_access_token_by_code('code')
userinfo = google_app.get_oauth_userinfo()
+
+ # 验证用户信息
self.assertEqual(userinfo.token, 'access_token')
- self.assertEqual(userinfo.openid, 'sub')
+ self.assertEqual(userinfo.openid, 'sub') # Google使用sub作为用户ID
@patch("oauth.oauthmanager.GitHubOauthManager.do_post")
@patch("oauth.oauthmanager.GitHubOauthManager.do_get")
def test_github_login(self, mock_do_get, mock_do_post):
+ """
+ 测试GitHub OAuth登录流程
+ """
github_app = self.get_app_by_type('github')
assert github_app
+
url = github_app.get_authorization_url()
+ # 验证GitHub授权URL包含必要信息
self.assertTrue("github.com" in url)
self.assertTrue("client_id" in url)
+
+ # 模拟GitHub的token响应(字符串格式)
mock_do_post.return_value = "access_token=gho_16C7e42F292c6912E7710c838347Ae178B4a&scope=repo%2Cgist&token_type=bearer"
+
+ # 模拟GitHub用户信息响应
mock_do_get.return_value = json.dumps({
"avatar_url": "avatar_url",
"name": "name",
"id": "id",
"email": "email",
})
+
token = github_app.get_access_token_by_code('code')
userinfo = github_app.get_oauth_userinfo()
+
+ # 验证用户信息
self.assertEqual(userinfo.token, 'gho_16C7e42F292c6912E7710c838347Ae178B4a')
self.assertEqual(userinfo.openid, 'id')
@patch("oauth.oauthmanager.FaceBookOauthManager.do_post")
@patch("oauth.oauthmanager.FaceBookOauthManager.do_get")
def test_facebook_login(self, mock_do_get, mock_do_post):
+ """
+ 测试Facebook OAuth登录流程
+ """
facebook_app = self.get_app_by_type('facebook')
assert facebook_app
+
url = facebook_app.get_authorization_url()
- self.assertTrue("facebook.com" in url)
+ self.assertTrue("facebook.com" in url) # 验证Facebook授权URL
+
+ # 模拟Facebook token响应
mock_do_post.return_value = json.dumps({
"access_token": "access_token",
})
+
+ # 模拟Facebook用户信息响应(嵌套结构)
mock_do_get.return_value = json.dumps({
"name": "name",
"id": "id",
@@ -134,14 +216,16 @@ class OauthLoginTest(TestCase):
}
}
})
+
token = facebook_app.get_access_token_by_code('code')
userinfo = facebook_app.get_oauth_userinfo()
+
self.assertEqual(userinfo.token, 'access_token')
@patch("oauth.oauthmanager.QQOauthManager.do_get", side_effect=[
- 'access_token=access_token&expires_in=3600',
- 'callback({"client_id":"appid","openid":"openid"} );',
- json.dumps({
+ 'access_token=access_token&expires_in=3600', # 第一次调用:获取token
+ 'callback({"client_id":"appid","openid":"openid"} );', # 第二次调用:获取openid
+ json.dumps({ # 第三次调用:获取用户信息
"nickname": "nickname",
"email": "email",
"figureurl": "figureurl",
@@ -149,21 +233,33 @@ class OauthLoginTest(TestCase):
})
])
def test_qq_login(self, mock_do_get):
+ """
+ 测试QQ OAuth登录流程
+ 使用side_effect模拟多次不同的API响应
+ """
qq_app = self.get_app_by_type('qq')
assert qq_app
+
url = qq_app.get_authorization_url()
- self.assertTrue("qq.com" in url)
+ self.assertTrue("qq.com" in url) # 验证QQ授权URL
+
token = qq_app.get_access_token_by_code('code')
userinfo = qq_app.get_oauth_userinfo()
+
self.assertEqual(userinfo.token, 'access_token')
@patch("oauth.oauthmanager.WBOauthManager.do_post")
@patch("oauth.oauthmanager.WBOauthManager.do_get")
def test_weibo_authoriz_login_with_email(self, mock_do_get, mock_do_post):
-
+ """
+ 测试包含邮箱的微博授权登录完整流程
+ 验证用户认证和会话管理
+ """
+ # 模拟获取access token
mock_do_post.return_value = json.dumps({"access_token": "access_token",
"uid": "uid"
})
+ # 模拟用户信息(包含邮箱)
mock_user_info = {
"avatar_large": "avatar_large",
"screen_name": "screen_name1",
@@ -172,25 +268,31 @@ class OauthLoginTest(TestCase):
}
mock_do_get.return_value = json.dumps(mock_user_info)
+ # 测试登录跳转
response = self.client.get('/oauth/oauthlogin?type=weibo')
self.assertEqual(response.status_code, 302)
self.assertTrue("api.weibo.com" in response.url)
+ # 测试授权回调
response = self.client.get('/oauth/authorize?type=weibo&code=code')
self.assertEqual(response.status_code, 302)
self.assertEqual(response.url, '/')
+ # 验证用户认证状态
user = auth.get_user(self.client)
assert user.is_authenticated
self.assertTrue(user.is_authenticated)
self.assertEqual(user.username, mock_user_info['screen_name'])
self.assertEqual(user.email, mock_user_info['email'])
+
+ # 登出后再次测试
self.client.logout()
response = self.client.get('/oauth/authorize?type=weibo&code=code')
self.assertEqual(response.status_code, 302)
self.assertEqual(response.url, '/')
+ # 再次验证用户认证状态
user = auth.get_user(self.client)
assert user.is_authenticated
self.assertTrue(user.is_authenticated)
@@ -200,10 +302,15 @@ class OauthLoginTest(TestCase):
@patch("oauth.oauthmanager.WBOauthManager.do_post")
@patch("oauth.oauthmanager.WBOauthManager.do_get")
def test_weibo_authoriz_login_without_email(self, mock_do_get, mock_do_post):
-
+ """
+ 测试不包含邮箱的微博授权登录流程
+ 验证邮箱补充流程
+ """
+ # 模拟获取access token
mock_do_post.return_value = json.dumps({"access_token": "access_token",
"uid": "uid"
})
+ # 模拟用户信息(不包含邮箱)
mock_user_info = {
"avatar_large": "avatar_large",
"screen_name": "screen_name1",
@@ -211,28 +318,34 @@ class OauthLoginTest(TestCase):
}
mock_do_get.return_value = json.dumps(mock_user_info)
+ # 测试登录跳转
response = self.client.get('/oauth/oauthlogin?type=weibo')
self.assertEqual(response.status_code, 302)
self.assertTrue("api.weibo.com" in response.url)
+ # 测试授权回调 - 应该重定向到邮箱补充页面
response = self.client.get('/oauth/authorize?type=weibo&code=code')
-
self.assertEqual(response.status_code, 302)
+ # 解析OAuth用户ID
oauth_user_id = int(response.url.split('/')[-1].split('.')[0])
self.assertEqual(response.url, f'/oauth/requireemail/{oauth_user_id}.html')
+ # 提交邮箱信息
response = self.client.post(response.url, {'email': 'test@gmail.com', 'oauthid': oauth_user_id})
-
self.assertEqual(response.status_code, 302)
+
+ # 生成邮箱验证签名
sign = get_sha256(settings.SECRET_KEY +
str(oauth_user_id) + settings.SECRET_KEY)
+ # 验证绑定成功URL
url = reverse('oauth:bindsuccess', kwargs={
'oauthid': oauth_user_id,
})
self.assertEqual(response.url, f'{url}?type=email')
+ # 验证邮箱确认流程
path = reverse('oauth:email_confirm', kwargs={
'id': oauth_user_id,
'sign': sign
@@ -240,10 +353,12 @@ class OauthLoginTest(TestCase):
response = self.client.get(path)
self.assertEqual(response.status_code, 302)
self.assertEqual(response.url, f'/oauth/bindsuccess/{oauth_user_id}.html?type=success')
+
+ # 验证最终用户状态
user = auth.get_user(self.client)
from oauth.models import OAuthUser
oauth_user = OAuthUser.objects.get(author=user)
self.assertTrue(user.is_authenticated)
self.assertEqual(user.username, mock_user_info['screen_name'])
self.assertEqual(user.email, 'test@gmail.com')
- self.assertEqual(oauth_user.pk, oauth_user_id)
+ self.assertEqual(oauth_user.pk, oauth_user_id)
\ No newline at end of file