update subtree

# Conflicts:
#	src/DjangoBlog/accounts/tests.py
#	src/DjangoBlog/blog/admin.py
#	src/DjangoBlog/blog/documents.py
#	src/DjangoBlog/blog/middleware.py
#	src/DjangoBlog/blog/views.py
#	src/DjangoBlog/comments/admin.py
#	src/DjangoBlog/oauth/oauthmanager.py
#	src/DjangoBlog/oauth/tests.py
develop
dynastxu 3 months ago
commit 43ea653c11

@ -77,3 +77,5 @@ uploads/
settings_production.py
werobot_session.db
bin/datas/
.env

@ -10,7 +10,6 @@ from django.core.exceptions import ValidationError
from django.forms import widgets
#shw 导入Django的国际化和翻译工具
from django.utils.translation import gettext_lazy as _
from . import utils
#shw 导入本地的BlogUser模型
from .models import BlogUser

@ -2,8 +2,8 @@
import django.contrib.auth.models
import django.contrib.auth.validators
import django.utils.timezone
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):

@ -1,7 +1,7 @@
# Generated by Django 4.2.5 on 2023-09-06 13:13
import django.utils.timezone
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):

@ -8,7 +8,6 @@ from django.urls import reverse
from django.utils.timezone import now
#shw 导入Django的国际化和翻译工具
from django.utils.translation import gettext_lazy as _
from djangoblog.utils import get_current_site

@ -4,6 +4,7 @@ from django.test import Client, RequestFactory, TestCase
from django.urls import reverse
#shw 导入Django的时区工具
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
#shw 导入本地的BlogUser模型
from accounts.models import BlogUser
@ -35,12 +36,12 @@ class AccountTest(TestCase):
self.new_test = "xxx123--=" #shw 定义一个测试用的新密码
def test_validate_account(self):
get_current_site().domain
site = get_current_site().domain
user = BlogUser.objects.create_superuser(
email="liangliangyy1@gmail.com",
username="liangliangyy1",
password="qwer!@#$ggg")
BlogUser.objects.get(username='liangliangyy1') #shw 从数据库中获取刚创建的超级用户
testuser = BlogUser.objects.get(username='liangliangyy1') #shw 从数据库中获取刚创建的超级用户
#shw 使用client模拟登录
loginresult = self.client.login(
@ -78,7 +79,7 @@ class AccountTest(TestCase):
0, len(
BlogUser.objects.filter(
email='user123@user.com')))
self.client.post(reverse('account:register'), {
response = self.client.post(reverse('account:register'), {
'username': 'user1233',
'email': 'user123@user.com',
'password1': 'password123!q@wE#R$T',

@ -49,7 +49,6 @@ def verify(email: str, code: str) -> typing.Optional[str]:
if cache_code != code:
#shw 如果不一致,返回一个翻译后的错误信息字符串
return gettext("Verification code error")
return None
def set_code(email: str, code: str):

@ -1,6 +1,6 @@
#shw 导入日志模块
import logging
from django.utils.translation import gettext_lazy as _
from django.conf import settings
#shw 导入Django的认证模块
from django.contrib import auth

@ -7,7 +7,7 @@ from django.utils.html import format_html
from django.utils.translation import gettext_lazy as _
# Register your models here.
from .models import Article
from .models import Article, Category, Tag, Links, SideBar, BlogSettings
# bjy: 为Article模型创建一个自定义的ModelForm
@ -23,25 +23,25 @@ class ArticleForm(forms.ModelForm):
# bjy: 定义一个admin动作用于将选中的文章发布
def makr_article_publish(queryset):
def makr_article_publish(modeladmin, request, queryset):
# bjy: 批量更新查询集中所有文章的状态为'p'(已发布)
queryset.update(status='p')
# bjy: 定义一个admin动作用于将选中的文章设为草稿
def draft_article(queryset):
def draft_article(modeladmin, request, queryset):
# bjy: 批量更新查询集中所有文章的状态为'd'(草稿)
queryset.update(status='d')
# bjy: 定义一个admin动作用于关闭选中文章的评论功能
def close_article_commentstatus(queryset):
def close_article_commentstatus(modeladmin, request, queryset):
# bjy: 批量更新查询集中所有文章的评论状态为'c'(关闭)
queryset.update(comment_status='c')
# bjy: 定义一个admin动作用于开启选中文章的评论功能
def open_article_commentstatus(queryset):
def open_article_commentstatus(modeladmin, request, queryset):
# bjy: 批量更新查询集中所有文章的评论状态为'o'(开启)
queryset.update(comment_status='o')

@ -232,26 +232,23 @@ class ArticleDocument(Document):
# bjy: 定义一个管理类用于操作ArticleDocument索引
class ArticleDocumentManager:
class ArticleDocumentManager():
def __init__(self):
# bjy: 初始化时创建索引
self.create_index()
@staticmethod
def create_index():
def create_index(self):
# bjy: 创建'blog'索引
ArticleDocument.init()
@staticmethod
def delete_index():
def delete_index(self):
# bjy: 删除'blog'索引
from elasticsearch import Elasticsearch
es = Elasticsearch(settings.ELASTICSEARCH_DSL['default']['hosts'])
es.indices.delete(index='blog', ignore=[400, 404])
@staticmethod
def convert_to_doc(articles):
def convert_to_doc(self, articles):
# bjy: 将Django的Article查询集转换为ArticleDocument对象列表
return [
ArticleDocument(
@ -285,8 +282,7 @@ class ArticleDocumentManager:
for doc in docs:
doc.save()
@staticmethod
def update_docs(docs):
def update_docs(self, docs):
# bjy: 更新一组文档
for doc in docs:
doc.save()

@ -1,10 +1,10 @@
# bjy: 从Django核心管理模块导入BaseCommand基类用于创建自定义管理命令
from django.core.management.base import BaseCommand
from blog.models import Article, Tag, Category
from djangoblog.spider_notify import SpiderNotify
# bjy: 从项目工具模块导入get_current_site函数用于获取当前站点域名等信息
from djangoblog.utils import get_current_site
from blog.models import Article, Tag, Category
# bjy: 获取当前站点的域名用于拼接完整URL
site = get_current_site().domain

@ -45,7 +45,7 @@ class OnlineMiddleware(object):
# bjy: 如果启用了Elasticsearch
if ELASTICSEARCH_ENABLED:
# bjy: 将耗时转换为毫秒并四舍五入
time_taken = round(cast_time * 1000, 2)
time_taken = round((cast_time) * 1000, 2)
# bjy: 获取请求的URL路径
url = request.path
# bjy: 导入Django的时区工具

@ -1,9 +1,10 @@
# Generated by Django 4.1.7 on 2023-03-02 07:14
import django.utils.timezone
import mdeditor.fields
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
import mdeditor.fields
class Migration(migrations.Migration):

@ -1,9 +1,10 @@
# Generated by Django 4.2.5 on 2023-09-06 13:13
import django.utils.timezone
import mdeditor.fields
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
import mdeditor.fields
class Migration(migrations.Migration):

@ -1,5 +1,7 @@
import hashlib
import logging
import random
import urllib
from django import template
from django.conf import settings
@ -12,11 +14,11 @@ from django.utils.safestring import mark_safe
from blog.models import Article, Category, Tag, Links, SideBar, LinkShowType
from comments.models import Comment
from djangoblog.plugin_manage import hooks
from djangoblog.utils import CommonMarkdown, sanitize_html
from djangoblog.utils import cache
from djangoblog.utils import get_current_site
from oauth.models import OAuthUser
from djangoblog.plugin_manage import hooks
logger = logging.getLogger(__name__)
@ -166,7 +168,7 @@ def load_breadcrumb(article):
names = article.get_category_tree()
from djangoblog.utils import get_blog_setting
blogsetting = get_blog_setting()
get_current_site().domain
site = get_current_site().domain
names.append((blogsetting.site_name, '/'))
names = names[::-1]
@ -361,7 +363,7 @@ def load_article_detail(article, isindex, user):
# 返回用户头像URL
# 模板使用方法: {{ email|gravatar_url:150 }}
@register.filter
def gravatar_url(email):
def gravatar_url(email, size=40):
"""获得用户头像 - 优先使用OAuth头像否则使用默认头像"""
cachekey = 'avatar/' + email
url = cache.get(cachekey)
@ -398,7 +400,7 @@ def gravatar_url(email):
@register.filter
def gravatar(email, size=40):
"""获得用户头像HTML标签"""
url = gravatar_url(email)
url = gravatar_url(email, size)
return mark_safe(
'<img src="%s" height="%d" width="%d" class="avatar" alt="用户头像">' %
(url, size, size))

@ -34,7 +34,7 @@ class ArticleTest(TestCase):
# bjy: 定义一个测试方法,用于验证文章相关的功能
def test_validate_article(self):
get_current_site().domain
site = get_current_site().domain
user = BlogUser.objects.get_or_create(
email="liangliangyy@gmail.com",
username="liangliangyy")[0]
@ -47,8 +47,8 @@ class ArticleTest(TestCase):
# bjy: 测试用户详情页是否能正常访问
response = self.client.get(user.get_absolute_url())
self.assertEqual(response.status_code, 200)
self.client.get('/admin/servermanager/emailsendlog/')
self.client.get('admin/admin/logentry/')
response = self.client.get('/admin/servermanager/emailsendlog/')
response = self.client.get('admin/admin/logentry/')
s = SideBar()
s.sequence = 1
s.name = 'test'
@ -160,8 +160,8 @@ class ArticleTest(TestCase):
# bjy: 测试获取Gravatar头像的模板标签
from blog.templatetags.blog_tags import gravatar_url, gravatar
gravatar_url('liangliangyy@gmail.com')
gravatar('liangliangyy@gmail.com')
u = gravatar_url('liangliangyy@gmail.com')
u = gravatar('liangliangyy@gmail.com')
# bjy: 创建并保存一个友情链接
link = Links(

@ -22,6 +22,7 @@ from haystack.views import SearchView
from blog.models import Article, Category, LinkShowType, Links, Tag
from comments.forms import CommentForm
from djangoblog.plugin_manage import hooks
from djangoblog.plugin_manage.hook_constants import ARTICLE_CONTENT_HOOK_NAME
from djangoblog.utils import cache, get_blog_setting, get_sha256
# bjy: 获取一个名为__name__的logger实例用于记录日志
@ -72,11 +73,11 @@ class ArticleListView(ListView):
# bjy: 从缓存中获取数据集,如果缓存不存在则查询数据库并存入缓存
def get_queryset_from_cache(self, cache_key):
"""
'''
缓存页面数据
:param cache_key: 缓存key
:return:
"""
'''
value = cache.get(cache_key)
if value:
logger.info('get view cache.key:{key}'.format(key=cache_key))
@ -90,10 +91,10 @@ class ArticleListView(ListView):
# bjy: 重写父类方法从缓存中获取queryset
def get_queryset(self):
"""
'''
重写默认从缓存获取数据
:return:
"""
'''
key = self.get_queryset_cache_key()
value = self.get_queryset_from_cache(key)
return value
@ -106,9 +107,9 @@ class ArticleListView(ListView):
# bjy: 首页视图继承自ArticleListView
class IndexView(ArticleListView):
"""
'''
首页
"""
'''
# 友情链接类型
link_type = LinkShowType.I
@ -125,9 +126,9 @@ class IndexView(ArticleListView):
# bjy: 文章详情页视图
class ArticleDetailView(DetailView):
"""
'''
文章详情页面
"""
'''
template_name = 'blog/article_detail.html'
model = Article
pk_url_kwarg = 'article_id'
@ -197,9 +198,9 @@ class ArticleDetailView(DetailView):
# bjy: 分类详情页视图
class CategoryDetailView(ArticleListView):
"""
'''
分类目录列表
"""
'''
page_type = "分类目录归档"
# bjy: 实现父类的抽象方法,获取分类下的文章数据
@ -244,9 +245,9 @@ class CategoryDetailView(ArticleListView):
# bjy: 作者详情页视图
class AuthorDetailView(ArticleListView):
"""
'''
作者详情页
"""
'''
page_type = '作者文章归档'
# bjy: 实现父类的抽象方法,生成作者页的缓存键
@ -274,9 +275,9 @@ class AuthorDetailView(ArticleListView):
# bjy: 标签详情页视图
class TagDetailView(ArticleListView):
"""
'''
标签列表页面
"""
'''
page_type = '分类标签归档'
# bjy: 实现父类的抽象方法,获取标签下的文章数据
@ -310,9 +311,9 @@ class TagDetailView(ArticleListView):
# bjy: 文章归档页视图
class ArchivesView(ArticleListView):
"""
'''
文章归档页面
"""
'''
page_type = '文章归档'
# bjy: 归档页不分页
paginate_by = None
@ -420,7 +421,7 @@ def page_not_found_view(
template_name='blog/error_page.html'):
if exception:
logger.error(exception)
request.get_full_path()
url = request.get_full_path()
return render(request,
template_name,
{'message': _('Sorry, the page you requested is not found, please click the home page to see other?'),
@ -451,6 +452,6 @@ def permission_denied_view(
# bjy: 清除缓存的视图
def clean_cache_view():
def clean_cache_view(request):
cache.clear()
return HttpResponse('ok')

@ -6,13 +6,13 @@ from django.utils.translation import gettext_lazy as _
# zy: 禁用评论状态 - 管理员动作函数,用于批量禁用评论
def disable_commentstatus(queryset):
def disable_commentstatus(modeladmin, request, queryset):
# zy: 将选中的评论集的is_enable字段更新为False禁用
queryset.update(is_enable=False)
# zy: 启用评论状态 - 管理员动作函数,用于批量启用评论
def enable_commentstatus(queryset):
def enable_commentstatus(modeladmin, request, queryset):
# zy: 将选中的评论集的is_enable字段更新为True启用
queryset.update(is_enable=True)

@ -1,8 +1,9 @@
# Generated by Django 4.1.7 on 2023-03-02 07:14
import django.utils.timezone
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):

@ -1,8 +1,9 @@
# Generated by Django 4.2.5 on 2023-09-06 13:13
import django.utils.timezone
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):

@ -45,7 +45,7 @@ send_email_signal = django.dispatch.Signal(
@receiver(send_email_signal)
def send_email_signal_handler(**kwargs):
def send_email_signal_handler(sender, **kwargs):
"""`xjj`
发送邮件信号的处理函数
@ -85,7 +85,7 @@ def send_email_signal_handler(**kwargs):
@receiver(oauth_user_login_signal)
def oauth_user_login_signal_handler(**kwargs):
def oauth_user_login_signal_handler(sender, **kwargs):
"""`xjj`
OAuth 用户登录信号处理函数
@ -109,8 +109,13 @@ def oauth_user_login_signal_handler(**kwargs):
@receiver(post_save)
def model_post_save_callback(
sender,
instance,
update_fields):
created,
raw,
using,
update_fields,
**kwargs):
"""`xjj`
模型保存后的回调函数用于处理缓存清理和搜索引擎通知等操作
@ -166,7 +171,7 @@ def model_post_save_callback(
@receiver(user_logged_in)
@receiver(user_logged_out)
def user_auth_callback(user):
def user_auth_callback(sender, request, user, **kwargs):
if user and user.username:
logger.info(user)
delete_sidebar_cache()

@ -73,8 +73,7 @@ class ElasticSearchBackend(BaseSearchBackend):
docs = self._get_models(models)
self.manager.rebuild(docs)
@staticmethod
def _delete(models):
def _delete(self, models):
"""`xjj`
删除指定模型对象
@ -207,8 +206,7 @@ class ElasticSearchBackend(BaseSearchBackend):
class ElasticSearchQuery(BaseSearchQuery):
@staticmethod
def _convert_datetime(date):
def _convert_datetime(self, date):
"""`xjj`
将日期时间对象转换为字符串格式

@ -36,8 +36,7 @@ class DjangoBlogFeed(Feed):
title = "且听风吟 大巧无工,重剑无锋. "
link = "/feed/"
@staticmethod
def author_name():
def author_name(self):
"""`xjj`
获取 RSS 订阅源的作者名称
@ -47,8 +46,7 @@ class DjangoBlogFeed(Feed):
"""
return get_user_model().objects.first().nickname
@staticmethod
def author_link():
def author_link(self):
"""`xjj`
获取 RSS 订阅源作者的链接地址
@ -58,8 +56,7 @@ class DjangoBlogFeed(Feed):
"""
return get_user_model().objects.first().get_absolute_url()
@staticmethod
def items():
def items(self):
"""`xjj`
获取 RSS 订阅源的文章列表
@ -95,8 +92,7 @@ class DjangoBlogFeed(Feed):
"""
return CommonMarkdown.get_markdown(item.body)
@staticmethod
def feed_copyright():
def feed_copyright(self):
"""`xjj`
获取 RSS 订阅源的版权信息

@ -112,28 +112,23 @@ class BasePlugin:
"""渲染文章底部组件"""
return None
@staticmethod
def render_article_top_widget():
def render_article_top_widget(self, context, **kwargs):
"""渲染文章顶部组件"""
return None
@staticmethod
def render_header_widget():
def render_header_widget(self, context, **kwargs):
"""渲染页头组件"""
return None
@staticmethod
def render_footer_widget():
def render_footer_widget(self, context, **kwargs):
"""渲染页脚组件"""
return None
@staticmethod
def render_comment_before_widget():
def render_comment_before_widget(self, context, **kwargs):
"""渲染评论前组件"""
return None
@staticmethod
def render_comment_after_widget():
def render_comment_after_widget(self, context, **kwargs):
"""渲染评论后组件"""
return None
@ -174,13 +169,11 @@ class BasePlugin:
"""获取插件JavaScript文件列表"""
return []
@staticmethod
def get_head_html():
def get_head_html(self, context=None):
"""获取需要插入到<head>中的HTML内容"""
return ""
@staticmethod
def get_body_html():
def get_body_html(self, context=None):
"""获取需要插入到<body>底部的HTML内容"""
return ""

@ -1,6 +1,5 @@
import logging
import os
import logging
from django.conf import settings
logger = logging.getLogger(__name__)

@ -15,6 +15,11 @@ from pathlib import Path
from django.utils.translation import gettext_lazy as _
import environ
from dotenv import load_dotenv
load_dotenv()
env = environ.Env()
def env_to_bool(env, default):
"""`xjj`
@ -120,14 +125,17 @@ WSGI_APPLICATION = 'djangoblog.wsgi.application'
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': os.environ.get('DJANGO_MYSQL_DATABASE') or 'djangoblog',
'USER': os.environ.get('DJANGO_MYSQL_USER') or 'root',
'PASSWORD': os.environ.get('DJANGO_MYSQL_PASSWORD') or 'root',
'HOST': os.environ.get('DJANGO_MYSQL_HOST') or '127.0.0.1',
'NAME': env('DJANGO_MYSQL_DATABASE'),
'USER': env('DJANGO_MYSQL_USER'),
'PASSWORD': env('DJANGO_MYSQL_PASSWORD'),
'HOST': env('DJANGO_MYSQL_HOST'),
'PORT': int(
os.environ.get('DJANGO_MYSQL_PORT') or 3306),
env('DJANGO_MYSQL_PORT')),
'OPTIONS': {
'charset': 'utf8mb4'},
'charset': 'utf8mb4',
'ssl_mode': 'VERIFY_IDENTITY',
'ssl': {'ca': env('DJANGO_MYSQL_SSL_CA')}
},
}}
# Password validation

@ -82,8 +82,7 @@ class ArticleSiteMap(Sitemap):
"""
return Article.objects.filter(status='p')
@staticmethod
def lastmod(obj):
def lastmod(self, obj):
"""`xjj`
获取指定文章对象的最后修改时间
@ -118,8 +117,7 @@ class CategorySiteMap(Sitemap):
"""
return Category.objects.all()
@staticmethod
def lastmod(obj):
def lastmod(self, obj):
"""`xjj`
获取分类对象的最后修改时间
@ -154,8 +152,7 @@ class TagSiteMap(Sitemap):
"""
return Tag.objects.all()
@staticmethod
def lastmod(obj):
def lastmod(self, obj):
"""`xjj`
获取指定标签对象的最后修改时间
@ -193,8 +190,7 @@ class UserSiteMap(Sitemap):
"""
return list(set(map(lambda x: x.author, Article.objects.all())))
@staticmethod
def lastmod(obj):
def lastmod(self, obj):
"""`xjj`
获取指定用户对象的最后修改时间

@ -26,7 +26,7 @@ from django.conf import settings
logger = logging.getLogger(__name__)
class SpiderNotify:
class SpiderNotify():
"""`xjj`
爬虫通知类用于向搜索引擎提交 URL 通知

@ -13,16 +13,15 @@ Including another URLconf
1. Import the include() function: from django.conf.urls import url, include
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
"""
import time
from django.conf import settings
from django.conf.urls.i18n import i18n_patterns
from django.conf.urls.static import static
from django.contrib.sitemaps.views import sitemap
from django.http import JsonResponse
from django.urls import path, include
from django.urls import re_path
from haystack.views import search_view_factory
from django.http import JsonResponse
import time
from blog.views import EsSearchView
from djangoblog.admin_site import admin_site
@ -44,7 +43,7 @@ handler500 = 'blog.views.server_error_view'
handle403 = 'blog.views.permission_denied_view'
def health_check():
def health_check(request):
"""
健康检查接口
简单返回服务健康状态

@ -52,7 +52,7 @@ def get_max_articleid_commentid():
"""
from blog.models import Article
from comments.models import Comment
return Article.objects.latest().pk, Comment.objects.latest().pk
return (Article.objects.latest().pk, Comment.objects.latest().pk)
def get_sha256(str):
@ -138,14 +138,14 @@ def cache_decorator(expiration=3 * 60):
def expire_view_cache(path, servername, serverport, key_prefix=None):
"""
'''
刷新视图缓存
:param path:url路径
:param servername:host
:param serverport:端口
:param key_prefix:前缀
:return:是否成功
"""
'''
from django.http import HttpRequest
from django.utils.cache import get_cache_key
@ -332,11 +332,11 @@ def get_blog_setting():
def save_user_avatar(url):
"""
'''
保存用户头像
:param url:头像url
:return: 本地路径
"""
'''
logger.info(url)
try:
@ -418,7 +418,7 @@ ALLOWED_CLASSES = [
's1', 'ss', 'bp', 'vc', 'vg', 'vi', 'il'
]
def class_filter(name, value):
def class_filter(tag, name, value):
"""`xjj`
自定义 class 属性过滤器

@ -29,11 +29,11 @@ import re
import shutil
import threading
import warnings
from datetime import datetime
import six
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from datetime import datetime
from django.utils.encoding import force_str
from haystack.backends import BaseEngine, BaseSearchBackend, BaseSearchQuery, EmptyResults, log_query
from haystack.constants import DJANGO_CT, DJANGO_ID, ID
@ -155,7 +155,7 @@ class WhooshSearchBackend(BaseSearchBackend):
connections[self.connection_alias].get_unified_index().all_searchfields())
self.parser = QueryParser(self.content_field_name, schema=self.schema)
if new_index:
if new_index is True:
self.index = self.storage.create_index(self.schema)
else:
try:
@ -230,7 +230,7 @@ class WhooshSearchBackend(BaseSearchBackend):
raise SearchBackendError(
"No fields were found in any search_indexes. Please correct this before attempting to search.")
return content_field_name, Schema(**schema_fields)
return (content_field_name, Schema(**schema_fields))
def update(self, index, iterable, commit=True):
"""`xjj`
@ -389,8 +389,7 @@ class WhooshSearchBackend(BaseSearchBackend):
self.index = self.index.refresh()
self.index.optimize()
@staticmethod
def calculate_page(start_offset=0, end_offset=None):
def calculate_page(self, start_offset=0, end_offset=None):
"""`xjj`
根据偏移量计算分页信息
@ -699,7 +698,7 @@ class WhooshSearchBackend(BaseSearchBackend):
# Deferred models will have a different class ("RealClass_Deferred_fieldname")
# which won't be in our registry:
model_instance._meta.concrete_model
model_klass = model_instance._meta.concrete_model
field_name = self.content_field_name
narrow_queries = set()
@ -944,8 +943,7 @@ class WhooshSearchBackend(BaseSearchBackend):
spelling_suggestion = ' '.join(suggested_words)
return spelling_suggestion
@staticmethod
def _from_python(value):
def _from_python(self, value):
"""
Converts Python values to a string for Whoosh.
@ -968,8 +966,7 @@ class WhooshSearchBackend(BaseSearchBackend):
value = force_str(value)
return value
@staticmethod
def _to_python(value):
def _to_python(self, value):
"""
Converts values from Whoosh to native Python values.
@ -1021,8 +1018,7 @@ class WhooshSearchBackend(BaseSearchBackend):
class WhooshSearchQuery(BaseSearchQuery):
@staticmethod
def _convert_datetime(date):
def _convert_datetime(self, date):
"""`xjj`
将日期时间对象转换为 Whoosh 可识别的字符串格式
@ -1079,7 +1075,7 @@ class WhooshSearchQuery(BaseSearchQuery):
str: 构建好的查询片段字符串
"""
from haystack import connections
''
query_frag = ''
is_datetime = False
if not hasattr(value, 'input_type_name'):
@ -1124,7 +1120,7 @@ class WhooshSearchQuery(BaseSearchQuery):
'fuzzy': u'%s~',
}
if not value.post_process:
if value.post_process is False:
query_frag = prepared_value
else:
if filter_type in [
@ -1143,7 +1139,7 @@ class WhooshSearchQuery(BaseSearchQuery):
if isinstance(prepared_value, six.string_types):
possible_values = prepared_value.split(' ')
else:
if is_datetime:
if is_datetime is True:
prepared_value = self._convert_datetime(
prepared_value)
@ -1169,7 +1165,7 @@ class WhooshSearchQuery(BaseSearchQuery):
pv = self.backend._from_python(possible_value)
if is_datetime:
if is_datetime is True:
pv = self._convert_datetime(pv)
if isinstance(pv, six.string_types) and not is_datetime:
@ -1196,7 +1192,7 @@ class WhooshSearchQuery(BaseSearchQuery):
prepared_value = Exact(prepared_value).prepare(self)
query_frag = filter_types[filter_type] % prepared_value
else:
if is_datetime:
if is_datetime is True:
prepared_value = self._convert_datetime(prepared_value)
query_frag = filter_types[filter_type] % prepared_value

@ -97,7 +97,6 @@ class OAuthUserAdmin(admin.ModelAdmin):
return format_html(
u'<a href="%s">%s</a>' %
(link, obj.author.nickname if obj.author.nickname else obj.author.email))
return None
def show_user_image(self, obj):
"""lrj
@ -113,7 +112,7 @@ class OAuthUserAdmin(admin.ModelAdmin):
img = obj.picture # 获取头像URL
return format_html(
u'<img src="%s" style="width:50px;height:50px"></img>' %
img)
(img))
# 设置自定义方法在Admin中的显示名称
link_to_usermodel.short_description = '用户' # 关联用户列标题

@ -1,8 +1,9 @@
# Generated by Django 4.1.7 on 2023-03-07 09:53
import django.utils.timezone
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):

@ -1,8 +1,9 @@
# Generated by Django 4.2.5 on 2023-09-06 13:13
import django.utils.timezone
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):

@ -0,0 +1,17 @@
# Generated by Django 5.2.7 on 2025-11-11 10:33
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('oauth', '0003_alter_oauthuser_nickname'),
]
operations = [
migrations.AlterModelOptions(
name='oauthconfig',
options={'ordering': ['-creation_time'], 'verbose_name': 'OAuth配置', 'verbose_name_plural': 'OAuth配置'},
),
]

@ -20,9 +20,9 @@ logger = logging.getLogger(__name__)
class OAuthAccessTokenException(Exception):
"""
'''
oauth授权失败异常
"""
'''
class BaseOauthManager(metaclass=ABCMeta):
@ -113,8 +113,7 @@ class BaseOauthManager(metaclass=ABCMeta):
"""
pass
@staticmethod
def do_get(url, params, headers=None):
def do_get(self, url, params, headers=None):
"""lrj
执行GET请求到第三方API
@ -130,8 +129,7 @@ class BaseOauthManager(metaclass=ABCMeta):
logger.info(rsp.text) # lrj记录响应日志
return rsp.text
@staticmethod
def do_post(url, params, headers=None):
def do_post(self, url, params, headers=None):
"""lrj
执行POST请求到第三方API
@ -364,7 +362,6 @@ class QQOauthManager(BaseOauthManager):
token = d['access_token']
self.access_token = token[0]
return token
return None
else:
raise OAuthAccessTokenException(rsp)
@ -383,7 +380,6 @@ class QQOauthManager(BaseOauthManager):
openid = str(obj['openid'])
self.openid = openid
return openid
return None
def get_oauth_userinfo(self):
openid = self.get_open_id()
@ -407,7 +403,6 @@ class QQOauthManager(BaseOauthManager):
if 'figureurl' in obj:
user.picture = str(obj['figureurl'])
return user
return None
def get_picture(self, metadata):
datas = json.loads(metadata)

@ -60,8 +60,7 @@ class OauthLoginTest(TestCase):
self.factory = RequestFactory() # lrj请求工厂
self.apps = self.init_apps() # lrj初始化所有OAuth应用配置
@staticmethod
def init_apps():
def init_apps(self):
"""lrj初始化所有OAuth平台配置"""
# lrj获取所有OAuth管理器子类并实例化
applications = [p() for p in BaseOauthManager.__subclasses__()]
@ -79,7 +78,6 @@ class OauthLoginTest(TestCase):
for app in self.apps:
if app.ICON_NAME.lower() == type:
return app
return None
@patch("oauth.oauthmanager.WBOauthManager.do_post")
@patch("oauth.oauthmanager.WBOauthManager.do_get")
@ -90,7 +88,7 @@ class OauthLoginTest(TestCase):
assert weibo_app #lrj 验证应用存在
# lrj测试授权URL生成
weibo_app.get_authorization_url()
url = weibo_app.get_authorization_url()
# lrj模拟微博API响应
mock_do_post.return_value = json.dumps({"access_token": "access_token",
@ -117,7 +115,7 @@ class OauthLoginTest(TestCase):
assert google_app # lrj验证应用存在
# lrj测试授权URL生成
google_app.get_authorization_url()
url = google_app.get_authorization_url()
# lrj模拟Google API响应
mock_do_post.return_value = json.dumps({
@ -130,7 +128,7 @@ class OauthLoginTest(TestCase):
"sub": "sub",
"email": "email",
})
google_app.get_access_token_by_code('code')
token = google_app.get_access_token_by_code('code')
userinfo = google_app.get_oauth_userinfo()
self.assertEqual(userinfo.token, 'access_token') # lrj验证访问令牌
self.assertEqual(userinfo.openid, 'sub') # lrj验证用户OpenID
@ -156,7 +154,7 @@ class OauthLoginTest(TestCase):
"id": "id",
"email": "email",
})
github_app.get_access_token_by_code('code')
token = github_app.get_access_token_by_code('code')
userinfo = github_app.get_oauth_userinfo()
self.assertEqual(userinfo.token, 'gho_16C7e42F292c6912E7710c838347Ae178B4a') # lrj验证访问令牌
self.assertEqual(userinfo.openid, 'id') # lrj验证用户OpenID
@ -187,7 +185,7 @@ class OauthLoginTest(TestCase):
}
}
})
facebook_app.get_access_token_by_code('code')
token = facebook_app.get_access_token_by_code('code')
userinfo = facebook_app.get_oauth_userinfo()
self.assertEqual(userinfo.token, 'access_token') # lrj验证访问令牌
@ -201,7 +199,7 @@ class OauthLoginTest(TestCase):
"openid": "openid",
}) # lrj获取用户信息响应
])
def test_qq_login(self):
def test_qq_login(self, mock_do_get):
"""lrj测试QQ OAuth登录流程"""
# lrj获取QQ OAuth应用
qq_app = self.get_app_by_type('qq')
@ -212,7 +210,7 @@ class OauthLoginTest(TestCase):
self.assertTrue("qq.com" in url) # lrj验证QQ域名
# lrj测试获取访问令牌和用户信息使用side_effect模拟多次调用
qq_app.get_access_token_by_code('code')
token = qq_app.get_access_token_by_code('code')
userinfo = qq_app.get_oauth_userinfo()
self.assertEqual(userinfo.token, 'access_token') # lrj验证访问令牌

@ -1,7 +1,7 @@
# Generated by Django 4.1.7 on 2023-03-02 07:14
import django.utils.timezone
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):

@ -42,7 +42,7 @@ class OwnTrackLogTest(TestCase):
rsp = self.client.get('/owntracks/show_maps')
self.assertEqual(rsp.status_code, 302)
BlogUser.objects.create_superuser(
user = BlogUser.objects.create_superuser(
email="liangliangyy1@gmail.com",
username="liangliangyy1",
password="liangliangyy1")

@ -1,5 +1,5 @@
from djangoblog.plugin_manage import hooks
from djangoblog.plugin_manage.base_plugin import BasePlugin
from djangoblog.plugin_manage import hooks
from djangoblog.plugin_manage.hook_constants import ARTICLE_CONTENT_HOOK_NAME
@ -14,8 +14,7 @@ class ArticleCopyrightPlugin(BasePlugin):
# 在这里将插件的方法注册到指定的钩子上
hooks.register(ARTICLE_CONTENT_HOOK_NAME, self.add_copyright_to_content)
@staticmethod
def add_copyright_to_content(content, **kwargs):
def add_copyright_to_content(self, content, *args, **kwargs):
"""
这个方法会被注册到 'the_content' 过滤器钩子上
它接收原始内容并返回添加了版权信息的新内容

@ -1,9 +1,8 @@
import logging
from blog.models import Article
from djangoblog.plugin_manage import hooks
from djangoblog.plugin_manage.base_plugin import BasePlugin
from djangoblog.plugin_manage import hooks
from djangoblog.plugin_manage.hook_constants import ARTICLE_DETAIL_LOAD
from blog.models import Article
logger = logging.getLogger(__name__)
@ -34,7 +33,7 @@ class ArticleRecommendationPlugin(BasePlugin):
"""注册钩子"""
hooks.register(ARTICLE_DETAIL_LOAD, self.on_article_detail_load)
def on_article_detail_load(self, article, context):
def on_article_detail_load(self, article, context, request, *args, **kwargs):
"""文章详情页加载时的处理"""
# 可以在这里预加载推荐数据到context中
recommendations = self.get_recommendations(article)
@ -195,8 +194,7 @@ class ArticleRecommendationPlugin(BasePlugin):
return valid_recommendations[:count]
@staticmethod
def get_popular_articles(count=3):
def get_popular_articles(self, count=3):
"""获取热门文章"""
return list(Article.objects.filter(
status='p'

@ -1,8 +1,7 @@
import re
from urllib.parse import urlparse
from djangoblog.plugin_manage import hooks
from djangoblog.plugin_manage.base_plugin import BasePlugin
from djangoblog.plugin_manage import hooks
from djangoblog.plugin_manage.hook_constants import ARTICLE_CONTENT_HOOK_NAME
@ -15,8 +14,7 @@ class ExternalLinksPlugin(BasePlugin):
def register_hooks(self):
hooks.register(ARTICLE_CONTENT_HOOK_NAME, self.process_external_links)
@staticmethod
def process_external_links(content):
def process_external_links(self, content, *args, **kwargs):
from djangoblog.utils import get_current_site
site_domain = get_current_site().domain

@ -1,9 +1,8 @@
import hashlib
import re
import hashlib
from urllib.parse import urlparse
from djangoblog.plugin_manage import hooks
from djangoblog.plugin_manage.base_plugin import BasePlugin
from djangoblog.plugin_manage import hooks
from djangoblog.plugin_manage.hook_constants import ARTICLE_CONTENT_HOOK_NAME
@ -28,7 +27,7 @@ class ImageOptimizationPlugin(BasePlugin):
def register_hooks(self):
hooks.register(ARTICLE_CONTENT_HOOK_NAME, self.optimize_images)
def optimize_images(self, content):
def optimize_images(self, content, *args, **kwargs):
"""
优化文章中的图片标签
"""
@ -64,8 +63,7 @@ class ImageOptimizationPlugin(BasePlugin):
return optimized_content
@staticmethod
def _parse_img_attributes(attr_string):
def _parse_img_attributes(self, attr_string):
"""
解析 img 标签的属性
"""
@ -152,8 +150,7 @@ class ImageOptimizationPlugin(BasePlugin):
return attrs
@staticmethod
def _build_img_tag(attrs):
def _build_img_tag(self, attrs):
"""
重新构建 img 标签
"""
@ -170,8 +167,7 @@ class ImageOptimizationPlugin(BasePlugin):
return f'<img {" ".join(attr_strings)}>'
@staticmethod
def _get_current_domain():
def _get_current_domain(self):
"""
获取当前网站域名
"""

@ -1,8 +1,7 @@
import math
import re
from djangoblog.plugin_manage import hooks
from djangoblog.plugin_manage.base_plugin import BasePlugin
from djangoblog.plugin_manage import hooks
from djangoblog.plugin_manage.hook_constants import ARTICLE_CONTENT_HOOK_NAME
@ -15,8 +14,7 @@ class ReadingTimePlugin(BasePlugin):
def register_hooks(self):
hooks.register(ARTICLE_CONTENT_HOOK_NAME, self.add_reading_time)
@staticmethod
def add_reading_time(content, **kwargs):
def add_reading_time(self, content, *args, **kwargs):
"""
计算阅读时间并添加到内容开头
只在文章详情页显示首页文章列表页不显示

@ -1,10 +1,9 @@
import json
from django.utils.html import strip_tags
from blog.models import Article, Category
from djangoblog.plugin_manage import hooks
from django.template.defaultfilters import truncatewords
from djangoblog.plugin_manage.base_plugin import BasePlugin
from djangoblog.plugin_manage import hooks
from blog.models import Article, Category, Tag
from djangoblog.utils import get_blog_setting
@ -17,8 +16,7 @@ class SeoOptimizerPlugin(BasePlugin):
def register_hooks(self):
hooks.register('head_meta', self.dispatch_seo_generation)
@staticmethod
def _get_article_seo_data(context, request, blog_setting):
def _get_article_seo_data(self, context, request, blog_setting):
article = context.get('article')
if not isinstance(article, Article):
return None
@ -63,8 +61,7 @@ class SeoOptimizerPlugin(BasePlugin):
"json_ld": structured_data
}
@staticmethod
def _get_category_seo_data(context, request, blog_setting):
def _get_category_seo_data(self, context, request, blog_setting):
category_name = context.get('tag_name')
if not category_name:
return None
@ -95,8 +92,7 @@ class SeoOptimizerPlugin(BasePlugin):
"json_ld": structured_data
}
@staticmethod
def _get_default_seo_data(request, blog_setting):
def _get_default_seo_data(self, context, request, blog_setting):
# Homepage and other default pages
structured_data = {
"@context": "https://schema.org",
@ -133,7 +129,7 @@ class SeoOptimizerPlugin(BasePlugin):
seo_data = self._get_category_seo_data(context, request, blog_setting)
if not seo_data:
seo_data = self._get_default_seo_data(request, blog_setting)
seo_data = self._get_default_seo_data(context, request, blog_setting)
json_ld_script = f'<script type="application/ld+json">{json.dumps(seo_data.get("json_ld", {}), ensure_ascii=False, indent=4)}</script>'

@ -1,5 +1,5 @@
from djangoblog.plugin_manage import hooks
from djangoblog.plugin_manage.base_plugin import BasePlugin
from djangoblog.plugin_manage import hooks
class ViewCountPlugin(BasePlugin):
@ -11,8 +11,7 @@ class ViewCountPlugin(BasePlugin):
def register_hooks(self):
hooks.register('after_article_body_get', self.record_view)
@staticmethod
def record_view(article):
def record_view(self, article, *args, **kwargs):
article.viewed()

Binary file not shown.

@ -14,8 +14,7 @@ class BlogApi:
sqs = sqs.load_all()
return sqs[:self.__max_takecount__]
@staticmethod
def get_category_lists():
def get_category_lists(self):
return Category.objects.all()
def get_category_articles(self, categoryname):

@ -44,8 +44,7 @@ class CommandHandler:
else:
return "未找到相关命令请输入hepme获得帮助。"
@staticmethod
def __run_command__(cmd):
def __run_command__(self, cmd):
try:
res = os.popen(cmd).read()
return res

@ -47,7 +47,7 @@ def convert_to_article_reply(articles, message):
@robot.filter(re.compile(r"^\?.*"))
def search(message):
def search(message, session):
s = message.content
searchstr = str(s).replace('?', '')
result = blogapi.search_articles(searchstr)
@ -60,14 +60,14 @@ def search(message):
@robot.filter(re.compile(r'^category\s*$', re.I))
def category():
def category(message, session):
categorys = blogapi.get_category_lists()
content = ','.join(map(lambda x: x.name, categorys))
return '所有文章分类目录:' + content
@robot.filter(re.compile(r'^recent\s*$', re.I))
def recents(message):
def recents(message, session):
articles = blogapi.get_recent_articles()
if articles:
reply = convert_to_article_reply(articles, message)
@ -77,7 +77,7 @@ def recents(message):
@robot.filter(re.compile('^help$', re.I))
def help():
def help(message, session):
return '''欢迎关注!
默认会与图灵机器人聊天~~
你可以通过下面这些命令来获得信息
@ -99,12 +99,12 @@ def help():
@robot.filter(re.compile(r'^weather\:.*$', re.I))
def weather():
def weather(message, session):
return "建设中..."
@robot.filter(re.compile(r'^idcard\:.*$', re.I))
def idcard():
def idcard(message, session):
return "建设中..."
@ -123,7 +123,7 @@ class MessageHandler:
try:
info = session[userid]
self.userinfo = jsonpickle.decode(info)
except Exception:
except Exception as e:
userinfo = WxUserInfo()
self.userinfo = userinfo
@ -179,7 +179,7 @@ class MessageHandler:
return ChatGPT.chat(info)
class WxUserInfo:
class WxUserInfo():
def __init__(self):
self.isAdmin = False
self.isPasswordSet = False

@ -1,4 +1,5 @@
from django.test import Client, RequestFactory, TestCase
from django.utils import timezone
from werobot.messages.messages import TextMessage
from accounts.models import BlogUser
@ -41,10 +42,10 @@ class ServerManagerTest(TestCase):
article.save()
s = TextMessage([])
s.content = "nice"
search(s)
rsp = category()
rsp = search(s, None)
rsp = category(None, None)
self.assertIsNotNone(rsp)
rsp = recents(None)
rsp = recents(None, None)
self.assertTrue(rsp != '暂时还没有文章')
cmd = commands()

Loading…
Cancel
Save