From 9bfc60fa606919efec2ecbfac79534e1acffe358 Mon Sep 17 00:00:00 2001 From: pgxy4rpc3 <1662607537@qq.com> Date: Sat, 27 Sep 2025 15:19:35 +0800 Subject: [PATCH 01/11] ADD file via upload --- mxw_评测.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 mxw_评测.txt diff --git a/mxw_评测.txt b/mxw_评测.txt new file mode 100644 index 0000000..ddd7d78 --- /dev/null +++ b/mxw_评测.txt @@ -0,0 +1,3 @@ +DjangoBlog是一个基于Django框架的典型博客系统,结构清晰、代码规范,非常适合Django初学者学习和二次开发。它实现了用户认证、文章管理、评论等核心功能,模板设计简洁,遵循了Django的最佳实践。 + +不过,其前端界面相对基础,缺乏响应式设计和现代化UI;功能也较为简单,没有标签分类、全文搜索等高级特性。作为教学范例或轻量级博客足够,但用于生产环境需要较多扩展开发。总体而言,是一个质量不错的入门级项目。 From df508a17d39092073bc17130b43c9345ae410bb4 Mon Sep 17 00:00:00 2001 From: plo7phx3z <3532144600@qq.com> Date: Sun, 28 Sep 2025 12:24:08 +0800 Subject: [PATCH 02/11] ADD file via upload --- zy.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 zy.txt diff --git a/zy.txt b/zy.txt new file mode 100644 index 0000000..d44c990 --- /dev/null +++ b/zy.txt @@ -0,0 +1 @@ +DjangoBlog 是一款基于 Python 3.10 和 Django 4.0 构建的高性能博客平台。它不仅提供了传统博客的所有核心功能,还通过一个灵活的插件系统,让您可以轻松扩展和定制您的网站。 \ No newline at end of file From 578fc20075cbe6c8185e8ffd092b17b7e080e433 Mon Sep 17 00:00:00 2001 From: p2l7q3zht <1687267877@qq.com> Date: Sun, 28 Sep 2025 17:11:48 +0800 Subject: [PATCH 03/11] Add 1.txt --- 1.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 1.txt diff --git a/1.txt b/1.txt new file mode 100644 index 0000000..bc8d537 --- /dev/null +++ b/1.txt @@ -0,0 +1 @@ +软件工程方法学 \ No newline at end of file From b24aca3f42103266041cdea1b4b5c02439614872 Mon Sep 17 00:00:00 2001 From: p2l7q3zht <1687267877@qq.com> Date: Sun, 28 Sep 2025 19:47:42 +0800 Subject: [PATCH 04/11] ADD file via upload --- 新建 文本文档 (2).txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 新建 文本文档 (2).txt diff --git a/新建 文本文档 (2).txt b/新建 文本文档 (2).txt new file mode 100644 index 0000000..65494da --- /dev/null +++ b/新建 文本文档 (2).txt @@ -0,0 +1 @@ +11111111111111111111111111111111111111111111111111 \ No newline at end of file From ed0ad8ae9f468734a1893f63a97cbeec945ae6a8 Mon Sep 17 00:00:00 2001 From: pgxy4rpc3 <1662607537@qq.com> Date: Mon, 6 Oct 2025 14:36:17 +0800 Subject: [PATCH 05/11] ADD file via upload --- ...ngoBlog开源代码的泛读报告 (1).docx | Bin 0 -> 354461 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/DjangoBlog开源代码的泛读报告 (1).docx diff --git a/doc/DjangoBlog开源代码的泛读报告 (1).docx b/doc/DjangoBlog开源代码的泛读报告 (1).docx new file mode 100644 index 0000000000000000000000000000000000000000..e27812a75f0cf9f1a86099ded5055b0e07aa7190 GIT binary patch literal 354461 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

ce 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

0TzfEFXEplc7X4JXXQsIbsSiET31Q>`VL19{UHk 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

l5#E@_dgBp)2I%N($mG5!8?} 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 Date: Thu, 9 Oct 2025 22:14:23 +0800 Subject: [PATCH 06/11] ADD file via upload --- 张扬2315304162软工一班.docx | Bin 0 -> 11665 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 张扬2315304162软工一班.docx diff --git a/张扬2315304162软工一班.docx b/张扬2315304162软工一班.docx new file mode 100644 index 0000000000000000000000000000000000000000..c7f11de20b98db3041f30052cef25ecf7d3349a4 GIT binary patch literal 11665 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 Date: Sat, 11 Oct 2025 20:01:07 +0800 Subject: [PATCH 07/11] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=EF=BC=9A=E5=88=9B=E5=BB=BAsrc=E5=92=8Cdoc=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E5=A4=B9=EF=BC=8C=E5=AE=8C=E6=88=90=E9=A6=96=E6=AC=A1?= =?UTF-8?q?=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .coveragerc | 10 + .dockerignore | 11 + .gitattributes | 6 + .github/ISSUE_TEMPLATE.md | 18 + .github/workflows/codeql-analysis.yml | 47 + .github/workflows/django.yml | 136 +++ .github/workflows/docker.yml | 43 + .github/workflows/publish-release.yml | 39 + .gitignore | 80 ++ Dockerfile | 15 + LICENSE | 20 + README.md | 158 +++ accounts/__init__.py | 0 accounts/admin.py | 59 + accounts/apps.py | 5 + accounts/forms.py | 117 ++ accounts/migrations/0001_initial.py | 49 + ...s_remove_bloguser_created_time_and_more.py | 46 + accounts/migrations/__init__.py | 0 accounts/models.py | 35 + accounts/templatetags/__init__.py | 0 accounts/tests.py | 207 ++++ accounts/urls.py | 28 + accounts/user_login_backend.py | 26 + accounts/utils.py | 49 + accounts/views.py | 204 ++++ blog/__init__.py | 0 blog/admin.py | 112 ++ blog/apps.py | 5 + blog/context_processors.py | 43 + blog/documents.py | 213 ++++ blog/forms.py | 19 + blog/management/__init__.py | 0 blog/management/commands/__init__.py | 0 blog/management/commands/build_index.py | 18 + .../management/commands/build_search_words.py | 13 + blog/management/commands/clear_cache.py | 11 + blog/management/commands/create_testdata.py | 40 + blog/management/commands/ping_baidu.py | 50 + blog/management/commands/sync_user_avatar.py | 47 + blog/middleware.py | 42 + blog/migrations/0001_initial.py | 137 +++ ...002_blogsettings_global_footer_and_more.py | 23 + .../0003_blogsettings_comment_need_review.py | 17 + ...de_blogsettings_analytics_code_and_more.py | 27 + ...options_alter_category_options_and_more.py | 300 +++++ .../0006_alter_blogsettings_options.py | 17 + blog/migrations/__init__.py | 0 blog/models.py | 376 ++++++ blog/search_indexes.py | 13 + blog/templatetags/__init__.py | 0 blog/templatetags/blog_tags.py | 344 ++++++ blog/tests.py | 232 ++++ blog/urls.py | 62 + blog/views.py | 379 ++++++ comments/__init__.py | 0 comments/admin.py | 47 + comments/apps.py | 5 + comments/forms.py | 13 + comments/migrations/0001_initial.py | 38 + .../0002_alter_comment_is_enable.py | 18 + ...ns_remove_comment_created_time_and_more.py | 60 + comments/migrations/__init__.py | 0 comments/models.py | 39 + comments/templatetags/__init__.py | 0 comments/templatetags/comments_tags.py | 30 + comments/tests.py | 109 ++ comments/urls.py | 11 + comments/utils.py | 38 + comments/views.py | 63 + deploy/docker-compose/docker-compose.es.yml | 48 + deploy/docker-compose/docker-compose.yml | 60 + deploy/entrypoint.sh | 31 + deploy/k8s/configmap.yaml | 119 ++ deploy/k8s/deployment.yaml | 274 +++++ deploy/k8s/gateway.yaml | 17 + deploy/k8s/pv.yaml | 94 ++ deploy/k8s/pvc.yaml | 60 + deploy/k8s/service.yaml | 80 ++ deploy/k8s/storageclass.yaml | 10 + deploy/nginx.conf | 50 + djangoblog/__init__.py | 1 + djangoblog/admin_site.py | 64 + djangoblog/apps.py | 11 + djangoblog/blog_signals.py | 122 ++ djangoblog/elasticsearch_backend.py | 183 +++ djangoblog/feeds.py | 40 + djangoblog/logentryadmin.py | 91 ++ djangoblog/plugin_manage/base_plugin.py | 41 + djangoblog/plugin_manage/hook_constants.py | 7 + djangoblog/plugin_manage/hooks.py | 44 + djangoblog/plugin_manage/loader.py | 19 + djangoblog/settings.py | 343 ++++++ djangoblog/sitemap.py | 59 + djangoblog/spider_notify.py | 21 + djangoblog/tests.py | 32 + djangoblog/urls.py | 64 + djangoblog/utils.py | 232 ++++ djangoblog/whoosh_cn_backend.py | 1044 +++++++++++++++++ djangoblog/wsgi.py | 16 + docs/README-en.md | 158 +++ docs/config-en.md | 64 + docs/config.md | 58 + docs/docker-en.md | 114 ++ docs/docker.md | 114 ++ docs/es.md | 28 + docs/imgs/alipay.jpg | Bin 0 -> 17961 bytes docs/imgs/pycharm_logo.png | Bin 0 -> 132045 bytes docs/imgs/wechat.jpg | Bin 0 -> 24722 bytes docs/k8s-en.md | 141 +++ docs/k8s.md | 141 +++ locale/en/LC_MESSAGES/django.mo | Bin 0 -> 11097 bytes locale/en/LC_MESSAGES/django.po | 685 +++++++++++ locale/zh_Hans/LC_MESSAGES/django.mo | Bin 0 -> 10321 bytes locale/zh_Hans/LC_MESSAGES/django.po | 667 +++++++++++ locale/zh_Hant/LC_MESSAGES/django.mo | Bin 0 -> 10268 bytes locale/zh_Hant/LC_MESSAGES/django.po | 668 +++++++++++ manage.py | 22 + oauth/__init__.py | 0 oauth/admin.py | 54 + oauth/apps.py | 5 + oauth/forms.py | 12 + oauth/migrations/0001_initial.py | 57 + ...ptions_alter_oauthuser_options_and_more.py | 86 ++ .../0003_alter_oauthuser_nickname.py | 18 + oauth/migrations/__init__.py | 0 oauth/models.py | 67 ++ oauth/oauthmanager.py | 504 ++++++++ oauth/templatetags/__init__.py | 1 + oauth/templatetags/oauth_tags.py | 22 + oauth/tests.py | 249 ++++ oauth/urls.py | 25 + oauth/views.py | 253 ++++ owntracks/__init__.py | 0 owntracks/admin.py | 7 + owntracks/apps.py | 5 + owntracks/migrations/0001_initial.py | 31 + ...0002_alter_owntracklog_options_and_more.py | 22 + owntracks/migrations/__init__.py | 0 owntracks/models.py | 20 + owntracks/tests.py | 64 + owntracks/urls.py | 12 + owntracks/views.py | 127 ++ plugins/__init__.py | 1 + plugins/article_copyright/__init__.py | 1 + plugins/article_copyright/plugin.py | 32 + plugins/external_links/__init__.py | 1 + plugins/external_links/plugin.py | 48 + plugins/reading_time/__init__.py | 1 + plugins/reading_time/plugin.py | 43 + plugins/seo_optimizer/__init__.py | 1 + plugins/seo_optimizer/plugin.py | 142 +++ plugins/view_count/__init__.py | 1 + plugins/view_count/plugin.py | 18 + requirements.txt | Bin 0 -> 2554 bytes servermanager/MemcacheStorage.py | 32 + servermanager/__init__.py | 0 servermanager/admin.py | 19 + servermanager/api/__init__.py | 1 + servermanager/api/blogapi.py | 27 + servermanager/api/commonapi.py | 64 + servermanager/apps.py | 5 + servermanager/migrations/0001_initial.py | 45 + ...002_alter_emailsendlog_options_and_more.py | 32 + servermanager/migrations/__init__.py | 0 servermanager/models.py | 33 + servermanager/robot.py | 187 +++ servermanager/tests.py | 79 ++ servermanager/urls.py | 10 + servermanager/views.py | 1 + templates/account/forget_password.html | 30 + templates/account/login.html | 46 + templates/account/registration_form.html | 29 + templates/account/result.html | 27 + templates/blog/article_archives.html | 60 + templates/blog/article_detail.html | 52 + templates/blog/article_index.html | 42 + templates/blog/error_page.html | 45 + templates/blog/links_list.html | 44 + templates/blog/tags/article_info.html | 74 ++ templates/blog/tags/article_meta_info.html | 59 + templates/blog/tags/article_pagination.html | 17 + templates/blog/tags/article_tag_list.html | 19 + templates/blog/tags/breadcrumb.html | 19 + templates/blog/tags/sidebar.html | 136 +++ templates/comments/tags/comment_item.html | 34 + .../comments/tags/comment_item_tree.html | 54 + templates/comments/tags/comment_list.html | 45 + templates/comments/tags/post_comment.html | 33 + templates/oauth/bindsuccess.html | 22 + templates/oauth/oauth_applications.html | 13 + templates/oauth/require_email.html | 46 + templates/owntracks/show_log_dates.html | 17 + templates/owntracks/show_maps.html | 135 +++ .../search/indexes/blog/article_text.txt | 3 + templates/search/search.html | 66 ++ templates/share_layout/adsense.html | 6 + templates/share_layout/base.html | 123 ++ templates/share_layout/base_account.html | 47 + templates/share_layout/footer.html | 56 + templates/share_layout/nav.html | 30 + templates/share_layout/nav_node.html | 19 + 202 files changed, 14469 insertions(+) create mode 100644 .coveragerc create mode 100644 .dockerignore create mode 100644 .gitattributes create mode 100644 .github/ISSUE_TEMPLATE.md create mode 100644 .github/workflows/codeql-analysis.yml create mode 100644 .github/workflows/django.yml create mode 100644 .github/workflows/docker.yml create mode 100644 .github/workflows/publish-release.yml create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 LICENSE create mode 100644 README.md create mode 100644 accounts/__init__.py create mode 100644 accounts/admin.py create mode 100644 accounts/apps.py create mode 100644 accounts/forms.py create mode 100644 accounts/migrations/0001_initial.py create mode 100644 accounts/migrations/0002_alter_bloguser_options_remove_bloguser_created_time_and_more.py create mode 100644 accounts/migrations/__init__.py create mode 100644 accounts/models.py create mode 100644 accounts/templatetags/__init__.py create mode 100644 accounts/tests.py create mode 100644 accounts/urls.py create mode 100644 accounts/user_login_backend.py create mode 100644 accounts/utils.py create mode 100644 accounts/views.py create mode 100644 blog/__init__.py create mode 100644 blog/admin.py create mode 100644 blog/apps.py create mode 100644 blog/context_processors.py create mode 100644 blog/documents.py create mode 100644 blog/forms.py create mode 100644 blog/management/__init__.py create mode 100644 blog/management/commands/__init__.py create mode 100644 blog/management/commands/build_index.py create mode 100644 blog/management/commands/build_search_words.py create mode 100644 blog/management/commands/clear_cache.py create mode 100644 blog/management/commands/create_testdata.py create mode 100644 blog/management/commands/ping_baidu.py create mode 100644 blog/management/commands/sync_user_avatar.py create mode 100644 blog/middleware.py create mode 100644 blog/migrations/0001_initial.py create mode 100644 blog/migrations/0002_blogsettings_global_footer_and_more.py create mode 100644 blog/migrations/0003_blogsettings_comment_need_review.py create mode 100644 blog/migrations/0004_rename_analyticscode_blogsettings_analytics_code_and_more.py create mode 100644 blog/migrations/0005_alter_article_options_alter_category_options_and_more.py create mode 100644 blog/migrations/0006_alter_blogsettings_options.py create mode 100644 blog/migrations/__init__.py create mode 100644 blog/models.py create mode 100644 blog/search_indexes.py create mode 100644 blog/templatetags/__init__.py create mode 100644 blog/templatetags/blog_tags.py create mode 100644 blog/tests.py create mode 100644 blog/urls.py create mode 100644 blog/views.py create mode 100644 comments/__init__.py create mode 100644 comments/admin.py create mode 100644 comments/apps.py create mode 100644 comments/forms.py create mode 100644 comments/migrations/0001_initial.py create mode 100644 comments/migrations/0002_alter_comment_is_enable.py create mode 100644 comments/migrations/0003_alter_comment_options_remove_comment_created_time_and_more.py create mode 100644 comments/migrations/__init__.py create mode 100644 comments/models.py create mode 100644 comments/templatetags/__init__.py create mode 100644 comments/templatetags/comments_tags.py create mode 100644 comments/tests.py create mode 100644 comments/urls.py create mode 100644 comments/utils.py create mode 100644 comments/views.py create mode 100644 deploy/docker-compose/docker-compose.es.yml create mode 100644 deploy/docker-compose/docker-compose.yml create mode 100644 deploy/entrypoint.sh create mode 100644 deploy/k8s/configmap.yaml create mode 100644 deploy/k8s/deployment.yaml create mode 100644 deploy/k8s/gateway.yaml create mode 100644 deploy/k8s/pv.yaml create mode 100644 deploy/k8s/pvc.yaml create mode 100644 deploy/k8s/service.yaml create mode 100644 deploy/k8s/storageclass.yaml create mode 100644 deploy/nginx.conf create mode 100644 djangoblog/__init__.py create mode 100644 djangoblog/admin_site.py create mode 100644 djangoblog/apps.py create mode 100644 djangoblog/blog_signals.py create mode 100644 djangoblog/elasticsearch_backend.py create mode 100644 djangoblog/feeds.py create mode 100644 djangoblog/logentryadmin.py create mode 100644 djangoblog/plugin_manage/base_plugin.py create mode 100644 djangoblog/plugin_manage/hook_constants.py create mode 100644 djangoblog/plugin_manage/hooks.py create mode 100644 djangoblog/plugin_manage/loader.py create mode 100644 djangoblog/settings.py create mode 100644 djangoblog/sitemap.py create mode 100644 djangoblog/spider_notify.py create mode 100644 djangoblog/tests.py create mode 100644 djangoblog/urls.py create mode 100644 djangoblog/utils.py create mode 100644 djangoblog/whoosh_cn_backend.py create mode 100644 djangoblog/wsgi.py create mode 100644 docs/README-en.md create mode 100644 docs/config-en.md create mode 100644 docs/config.md create mode 100644 docs/docker-en.md create mode 100644 docs/docker.md create mode 100644 docs/es.md create mode 100644 docs/imgs/alipay.jpg create mode 100644 docs/imgs/pycharm_logo.png create mode 100644 docs/imgs/wechat.jpg create mode 100644 docs/k8s-en.md create mode 100644 docs/k8s.md create mode 100644 locale/en/LC_MESSAGES/django.mo create mode 100644 locale/en/LC_MESSAGES/django.po create mode 100644 locale/zh_Hans/LC_MESSAGES/django.mo create mode 100644 locale/zh_Hans/LC_MESSAGES/django.po create mode 100644 locale/zh_Hant/LC_MESSAGES/django.mo create mode 100644 locale/zh_Hant/LC_MESSAGES/django.po create mode 100644 manage.py create mode 100644 oauth/__init__.py create mode 100644 oauth/admin.py create mode 100644 oauth/apps.py create mode 100644 oauth/forms.py create mode 100644 oauth/migrations/0001_initial.py create mode 100644 oauth/migrations/0002_alter_oauthconfig_options_alter_oauthuser_options_and_more.py create mode 100644 oauth/migrations/0003_alter_oauthuser_nickname.py create mode 100644 oauth/migrations/__init__.py create mode 100644 oauth/models.py create mode 100644 oauth/oauthmanager.py create mode 100644 oauth/templatetags/__init__.py create mode 100644 oauth/templatetags/oauth_tags.py create mode 100644 oauth/tests.py create mode 100644 oauth/urls.py create mode 100644 oauth/views.py create mode 100644 owntracks/__init__.py create mode 100644 owntracks/admin.py create mode 100644 owntracks/apps.py create mode 100644 owntracks/migrations/0001_initial.py create mode 100644 owntracks/migrations/0002_alter_owntracklog_options_and_more.py create mode 100644 owntracks/migrations/__init__.py create mode 100644 owntracks/models.py create mode 100644 owntracks/tests.py create mode 100644 owntracks/urls.py create mode 100644 owntracks/views.py create mode 100644 plugins/__init__.py create mode 100644 plugins/article_copyright/__init__.py create mode 100644 plugins/article_copyright/plugin.py create mode 100644 plugins/external_links/__init__.py create mode 100644 plugins/external_links/plugin.py create mode 100644 plugins/reading_time/__init__.py create mode 100644 plugins/reading_time/plugin.py create mode 100644 plugins/seo_optimizer/__init__.py create mode 100644 plugins/seo_optimizer/plugin.py create mode 100644 plugins/view_count/__init__.py create mode 100644 plugins/view_count/plugin.py create mode 100644 requirements.txt create mode 100644 servermanager/MemcacheStorage.py create mode 100644 servermanager/__init__.py create mode 100644 servermanager/admin.py create mode 100644 servermanager/api/__init__.py create mode 100644 servermanager/api/blogapi.py create mode 100644 servermanager/api/commonapi.py create mode 100644 servermanager/apps.py create mode 100644 servermanager/migrations/0001_initial.py create mode 100644 servermanager/migrations/0002_alter_emailsendlog_options_and_more.py create mode 100644 servermanager/migrations/__init__.py create mode 100644 servermanager/models.py create mode 100644 servermanager/robot.py create mode 100644 servermanager/tests.py create mode 100644 servermanager/urls.py create mode 100644 servermanager/views.py create mode 100644 templates/account/forget_password.html create mode 100644 templates/account/login.html create mode 100644 templates/account/registration_form.html create mode 100644 templates/account/result.html create mode 100644 templates/blog/article_archives.html create mode 100644 templates/blog/article_detail.html create mode 100644 templates/blog/article_index.html create mode 100644 templates/blog/error_page.html create mode 100644 templates/blog/links_list.html create mode 100644 templates/blog/tags/article_info.html create mode 100644 templates/blog/tags/article_meta_info.html create mode 100644 templates/blog/tags/article_pagination.html create mode 100644 templates/blog/tags/article_tag_list.html create mode 100644 templates/blog/tags/breadcrumb.html create mode 100644 templates/blog/tags/sidebar.html create mode 100644 templates/comments/tags/comment_item.html create mode 100644 templates/comments/tags/comment_item_tree.html create mode 100644 templates/comments/tags/comment_list.html create mode 100644 templates/comments/tags/post_comment.html create mode 100644 templates/oauth/bindsuccess.html create mode 100644 templates/oauth/oauth_applications.html create mode 100644 templates/oauth/require_email.html create mode 100644 templates/owntracks/show_log_dates.html create mode 100644 templates/owntracks/show_maps.html create mode 100644 templates/search/indexes/blog/article_text.txt create mode 100644 templates/search/search.html create mode 100644 templates/share_layout/adsense.html create mode 100644 templates/share_layout/base.html create mode 100644 templates/share_layout/base_account.html create mode 100644 templates/share_layout/footer.html create mode 100644 templates/share_layout/nav.html create mode 100644 templates/share_layout/nav_node.html diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..9757484 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,10 @@ +[run] +source = . +include = *.py +omit = + *migrations* + *tests* + *.html + *whoosh_cn_backend* + *settings.py* + *venv* diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..2818c38 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,11 @@ +bin/data/ +# virtualenv +venv/ +collectedstatic/ +djangoblog/whoosh_index/ +uploads/ +settings_production.py +*.md +docs/ +logs/ +static/ \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..fd52ece --- /dev/null +++ b/.gitattributes @@ -0,0 +1,6 @@ +blog/static/* linguist-vendored +*.js linguist-vendored +*.css linguist-vendored +* text=auto +*.sh text eol=lf +*.conf text eol=lf \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..2b5b7aa --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,18 @@ + + +**我确定我已经查看了** (标注`[ ]`为`[x]`) + +- [ ] [DjangoBlog的readme](https://github.com/liangliangyy/DjangoBlog/blob/master/README.md) +- [ ] [配置说明](https://github.com/liangliangyy/DjangoBlog/blob/master/bin/config.md) +- [ ] [其他 Issues](https://github.com/liangliangyy/DjangoBlog/issues) + +---- + +**我要申请** (标注`[ ]`为`[x]`) + +- [ ] BUG 反馈 +- [ ] 添加新的特性或者功能 +- [ ] 请求技术支持 diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000..6b76522 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,47 @@ +name: "CodeQL" + +on: + push: + branches: + - master + - dev + paths-ignore: + - '**/*.md' + - '**/*.css' + - '**/*.js' + - '**/*.yml' + - '**/*.txt' + pull_request: + branches: + - master + - dev + paths-ignore: + - '**/*.md' + - '**/*.css' + - '**/*.js' + - '**/*.yml' + - '**/*.txt' + schedule: + - cron: '30 1 * * 0' + + +jobs: + CodeQL-Build: + runs-on: ubuntu-latest + permissions: + security-events: write + actions: read + contents: read + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 \ No newline at end of file diff --git a/.github/workflows/django.yml b/.github/workflows/django.yml new file mode 100644 index 0000000..94baea9 --- /dev/null +++ b/.github/workflows/django.yml @@ -0,0 +1,136 @@ +name: Django CI + +on: + push: + branches: + - master + - dev + paths-ignore: + - '**/*.md' + - '**/*.css' + - '**/*.js' + pull_request: + branches: + - master + - dev + paths-ignore: + - '**/*.md' + - '**/*.css' + - '**/*.js' + +jobs: + build-normal: + runs-on: ubuntu-latest + strategy: + max-parallel: 4 + matrix: + python-version: ["3.10","3.11" ] + + steps: + - name: Start MySQL + uses: samin/mysql-action@v1.3 + with: + host port: 3306 + container port: 3306 + character set server: utf8mb4 + collation server: utf8mb4_general_ci + mysql version: latest + mysql root password: root + mysql database: djangoblog + mysql user: root + mysql password: root + + - uses: actions/checkout@v3 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + cache: 'pip' + - name: Install Dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + - name: Run Tests + env: + DJANGO_MYSQL_PASSWORD: root + DJANGO_MYSQL_HOST: 127.0.0.1 + run: | + python manage.py makemigrations + python manage.py migrate + python manage.py test + + build-with-es: + runs-on: ubuntu-latest + strategy: + max-parallel: 4 + matrix: + python-version: ["3.10","3.11" ] + + steps: + - name: Start MySQL + uses: samin/mysql-action@v1.3 + with: + host port: 3306 + container port: 3306 + character set server: utf8mb4 + collation server: utf8mb4_general_ci + mysql version: latest + mysql root password: root + mysql database: djangoblog + mysql user: root + mysql password: root + + - name: Configure sysctl limits + run: | + sudo swapoff -a + sudo sysctl -w vm.swappiness=1 + sudo sysctl -w fs.file-max=262144 + sudo sysctl -w vm.max_map_count=262144 + + - uses: miyataka/elasticsearch-github-actions@1 + + with: + stack-version: '7.12.1' + plugins: 'https://release.infinilabs.com/analysis-ik/stable/elasticsearch-analysis-ik-7.12.1.zip' + + + - uses: actions/checkout@v3 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + cache: 'pip' + - name: Install Dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + - name: Run Tests + env: + DJANGO_MYSQL_PASSWORD: root + DJANGO_MYSQL_HOST: 127.0.0.1 + DJANGO_ELASTICSEARCH_HOST: 127.0.0.1:9200 + run: | + python manage.py makemigrations + python manage.py migrate + coverage run manage.py test + coverage xml + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v1 + + docker: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Build and push + uses: docker/build-push-action@v3 + with: + context: . + push: false + tags: djangoblog/djangoblog:dev diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 0000000..a312e2f --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,43 @@ +name: docker + +on: + push: + paths-ignore: + - '**/*.md' + - '**/*.yml' + branches: + - 'master' + - 'dev' + +jobs: + docker: + runs-on: ubuntu-latest + steps: + - name: Set env to docker dev tag + if: endsWith(github.ref, '/dev') + run: | + echo "DOCKER_TAG=test" >> $GITHUB_ENV + - name: Set env to docker latest tag + if: endsWith(github.ref, '/master') + run: | + echo "DOCKER_TAG=latest" >> $GITHUB_ENV + - name: Checkout + uses: actions/checkout@v3 + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Login to DockerHub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Build and push + uses: docker/build-push-action@v3 + with: + context: . + push: true + tags: ${{ secrets.DOCKERHUB_USERNAME }}/djangoblog:${{env.DOCKER_TAG}} + + diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml new file mode 100644 index 0000000..5eb0853 --- /dev/null +++ b/.github/workflows/publish-release.yml @@ -0,0 +1,39 @@ +name: publish release + +on: + release: + types: [ published ] + +jobs: + docker: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Docker meta + id: meta + uses: docker/metadata-action@v3 + with: + images: name/app + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + - name: Login to DockerHub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Build and push + uses: docker/build-push-action@v3 + with: + context: . + push: true + platforms: | + linux/amd64 + linux/arm64 + linux/arm/v7 + linux/arm/v6 + linux/386 + tags: ${{ secrets.DOCKERHUB_USERNAME }}/djangoblog:${{ github.event.release.tag_name }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3015816 --- /dev/null +++ b/.gitignore @@ -0,0 +1,80 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover + +# Translations +*.pot + +# Django stuff: +*.log +logs/ + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + + +# PyCharm +# http://www.jetbrains.com/pycharm/webhelp/project.html +.idea +.iml +static/ +# virtualenv +venv/ + +collectedstatic/ +djangoblog/whoosh_index/ +google93fd32dbd906620a.html +baidu_verify_FlHL7cUyC9.html +BingSiteAuth.xml +cb9339dbe2ff86a5aa169d28dba5f615.txt +werobot_session.* +django.jpg +uploads/ +settings_production.py +werobot_session.db +bin/datas/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..80b46ac --- /dev/null +++ b/Dockerfile @@ -0,0 +1,15 @@ +FROM python:3.11 +ENV PYTHONUNBUFFERED 1 +WORKDIR /code/djangoblog/ +RUN apt-get update && \ + apt-get install default-libmysqlclient-dev gettext -y && \ + rm -rf /var/lib/apt/lists/* +ADD requirements.txt requirements.txt +RUN pip install --upgrade pip && \ + pip install --no-cache-dir -r requirements.txt && \ + pip install --no-cache-dir gunicorn[gevent] && \ + pip cache purge + +ADD . . +RUN chmod +x /code/djangoblog/deploy/entrypoint.sh +ENTRYPOINT ["/code/djangoblog/deploy/entrypoint.sh"] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3b08474 --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2025 车亮亮 + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..56aa4cc --- /dev/null +++ b/README.md @@ -0,0 +1,158 @@ +# DjangoBlog + +

+ Django CI + CodeQL + codecov + license +

+ +

+ 一款功能强大、设计优雅的现代化博客系统 +
+ English简体中文 +

+ +--- + +DjangoBlog 是一款基于 Python 3.10 和 Django 4.0 构建的高性能博客平台。它不仅提供了传统博客的所有核心功能,还通过一个灵活的插件系统,让您可以轻松扩展和定制您的网站。无论您是个人博主、技术爱好者还是内容创作者,DjangoBlog 都旨在为您提供一个稳定、高效且易于维护的写作和发布环境。 + +## ✨ 特性亮点 + +- **强大的内容管理**: 支持文章、独立页面、分类和标签的完整管理。内置强大的 Markdown 编辑器,支持代码语法高亮。 +- **全文搜索**: 集成搜索引擎,提供快速、精准的文章内容搜索。 +- **互动评论系统**: 支持回复、邮件提醒等功能,评论内容同样支持 Markdown。 +- **灵活的侧边栏**: 可自定义展示最新文章、最多阅读、标签云等模块。 +- **社交化登录**: 内置 OAuth 支持,已集成 Google, GitHub, Facebook, 微博, QQ 等主流平台。 +- **高性能缓存**: 原生支持 Redis 缓存,并提供自动刷新机制,确保网站高速响应。 +- **SEO 友好**: 具备基础 SEO 功能,新内容发布后可自动通知 Google 和百度。 +- **便捷的插件系统**: 通过创建独立的插件来扩展博客功能,代码解耦,易于维护。我们已经通过插件实现了文章浏览计数、SEO 优化等功能! +- **集成图床**: 内置简单的图床功能,方便图片上传和管理。 +- **自动化前端**: 集成 `django-compressor`,自动压缩和优化 CSS 及 JavaScript 文件。 +- **健壮的运维**: 内置网站异常邮件提醒和微信公众号管理功能。 + +## 🛠️ 技术栈 + +- **后端**: Python 3.10, Django 4.0 +- **数据库**: MySQL, SQLite (可配置) +- **缓存**: Redis +- **前端**: HTML5, CSS3, JavaScript +- **搜索**: Whoosh, Elasticsearch (可配置) +- **编辑器**: Markdown (mdeditor) + +## 🚀 快速开始 + +### 1. 环境准备 + +确保您的系统中已安装 Python 3.10+ 和 MySQL/MariaDB。 + +### 2. 克隆与安装 + +```bash +# 克隆项目到本地 +git clone https://github.com/liangliangyy/DjangoBlog.git +cd DjangoBlog + +# 安装依赖 +pip install -r requirements.txt +``` + +### 3. 项目配置 + +- **数据库**: + 打开 `djangoblog/settings.py` 文件,找到 `DATABASES` 配置项,修改为您的 MySQL 连接信息。 + + ```python + DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': 'djangoblog', + 'USER': 'root', + 'PASSWORD': 'your_password', + 'HOST': '127.0.0.1', + 'PORT': 3306, + } + } + ``` + 在 MySQL 中创建数据库: + ```sql + CREATE DATABASE `djangoblog` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + ``` + +- **更多配置**: + 关于邮件发送、OAuth 登录、缓存等更多高级配置,请参阅我们的 [详细配置文档](/docs/config.md)。 + +### 4. 初始化数据库 + +```bash +python manage.py makemigrations +python manage.py migrate + +# 创建一个超级管理员账户 +python manage.py createsuperuser +``` + +### 5. 运行项目 + +```bash +# (可选) 生成一些测试数据 +python manage.py create_testdata + +# (可选) 收集和压缩静态文件 +python manage.py collectstatic --noinput +python manage.py compress --force + +# 启动开发服务器 +python manage.py runserver +``` + +现在,在您的浏览器中访问 `http://127.0.0.1:8000/`,您应该能看到 DjangoBlog 的首页了! + +## 部署 + +- **传统部署**: 我们为您准备了非常详细的 [服务器部署教程](https://www.lylinux.net/article/2019/8/5/58.html)。 +- **Docker 部署**: 项目已全面支持 Docker。如果您熟悉容器化技术,请参考 [Docker 部署文档](/docs/docker.md) 来快速启动。 +- **Kubernetes 部署**: 我们也提供了完整的 [Kubernetes 部署指南](/docs/k8s.md),助您轻松上云。 + +## 🧩 插件系统 + +插件系统是 DjangoBlog 的核心特色之一。它允许您在不修改核心代码的情况下,通过编写独立的插件来为您的博客添加新功能。 + +- **工作原理**: 插件通过在预定义的“钩子”上注册回调函数来工作。例如,当一篇文章被渲染时,`after_article_body_get` 钩子会被触发,所有注册到此钩子的函数都会被执行。 +- **现有插件**: `view_count`(浏览计数), `seo_optimizer`(SEO优化)等都是通过插件系统实现的。 +- **开发您自己的插件**: 只需在 `plugins` 目录下创建一个新的文件夹,并编写您的 `plugin.py`。欢迎探索并为 DjangoBlog 社区贡献您的创意! + +## 🤝 贡献指南 + +我们热烈欢迎任何形式的贡献!如果您有好的想法或发现了 Bug,请随时提交 Issue 或 Pull Request。 + +## 📄 许可证 + +本项目基于 [MIT License](LICENSE) 开源。 + +--- + +## ❤️ 支持与赞助 + +如果您觉得这个项目对您有帮助,并且希望支持我继续维护和开发新功能,欢迎请我喝杯咖啡!您的每一份支持都是我前进的最大动力。 + +

+ 支付宝赞助 + 微信赞助 +

+

+ (左) 支付宝 / (右) 微信 +

+ +## 🙏 鸣谢 + +特别感谢 **JetBrains** 为本项目提供的免费开源许可证。 + +

+ + JetBrains Logo + +

+ +--- +> 如果本项目帮助到了你,请在[这里](https://github.com/liangliangyy/DjangoBlog/issues/214)留下你的网址,让更多的人看到。您的回复将会是我继续更新维护下去的动力。 diff --git a/accounts/__init__.py b/accounts/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/accounts/admin.py b/accounts/admin.py new file mode 100644 index 0000000..32e483c --- /dev/null +++ b/accounts/admin.py @@ -0,0 +1,59 @@ +from django import forms +from django.contrib.auth.admin import UserAdmin +from django.contrib.auth.forms import UserChangeForm +from django.contrib.auth.forms import UsernameField +from django.utils.translation import gettext_lazy as _ + +# Register your models here. +from .models import BlogUser + + +class BlogUserCreationForm(forms.ModelForm): + password1 = forms.CharField(label=_('password'), widget=forms.PasswordInput) + password2 = forms.CharField(label=_('Enter password again'), widget=forms.PasswordInput) + + class Meta: + model = BlogUser + fields = ('email',) + + def clean_password2(self): + # Check that the two password entries match + password1 = self.cleaned_data.get("password1") + password2 = self.cleaned_data.get("password2") + if password1 and password2 and password1 != password2: + raise forms.ValidationError(_("passwords do not match")) + return password2 + + def save(self, commit=True): + # Save the provided password in hashed format + user = super().save(commit=False) + user.set_password(self.cleaned_data["password1"]) + if commit: + user.source = 'adminsite' + user.save() + return user + + +class BlogUserChangeForm(UserChangeForm): + class Meta: + model = BlogUser + fields = '__all__' + field_classes = {'username': UsernameField} + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + +class BlogUserAdmin(UserAdmin): + form = BlogUserChangeForm + add_form = BlogUserCreationForm + list_display = ( + 'id', + 'nickname', + 'username', + 'email', + 'last_login', + 'date_joined', + 'source') + list_display_links = ('id', 'username') + ordering = ('-id',) diff --git a/accounts/apps.py b/accounts/apps.py new file mode 100644 index 0000000..9b3fc5a --- /dev/null +++ b/accounts/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class AccountsConfig(AppConfig): + name = 'accounts' diff --git a/accounts/forms.py b/accounts/forms.py new file mode 100644 index 0000000..fce4137 --- /dev/null +++ b/accounts/forms.py @@ -0,0 +1,117 @@ +from django import forms +from django.contrib.auth import get_user_model, password_validation +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 + + +class LoginForm(AuthenticationForm): + def __init__(self, *args, **kwargs): + super(LoginForm, self).__init__(*args, **kwargs) + self.fields['username'].widget = widgets.TextInput( + attrs={'placeholder': "username", "class": "form-control"}) + self.fields['password'].widget = widgets.PasswordInput( + attrs={'placeholder': "password", "class": "form-control"}) + + +class RegisterForm(UserCreationForm): + def __init__(self, *args, **kwargs): + super(RegisterForm, self).__init__(*args, **kwargs) + + self.fields['username'].widget = widgets.TextInput( + attrs={'placeholder': "username", "class": "form-control"}) + self.fields['email'].widget = widgets.EmailInput( + attrs={'placeholder': "email", "class": "form-control"}) + self.fields['password1'].widget = widgets.PasswordInput( + attrs={'placeholder': "password", "class": "form-control"}) + self.fields['password2'].widget = widgets.PasswordInput( + attrs={'placeholder': "repeat password", "class": "form-control"}) + + def clean_email(self): + email = self.cleaned_data['email'] + if get_user_model().objects.filter(email=email).exists(): + raise ValidationError(_("email already exists")) + return email + + class Meta: + model = get_user_model() + fields = ("username", "email") + + +class ForgetPasswordForm(forms.Form): + new_password1 = forms.CharField( + label=_("New password"), + widget=forms.PasswordInput( + attrs={ + "class": "form-control", + 'placeholder': _("New password") + } + ), + ) + + new_password2 = forms.CharField( + label="确认密码", + widget=forms.PasswordInput( + attrs={ + "class": "form-control", + 'placeholder': _("Confirm password") + } + ), + ) + + email = forms.EmailField( + label='邮箱', + widget=forms.TextInput( + attrs={ + 'class': 'form-control', + 'placeholder': _("Email") + } + ), + ) + + code = forms.CharField( + label=_('Code'), + widget=forms.TextInput( + attrs={ + 'class': 'form-control', + 'placeholder': _("Code") + } + ), + ) + + def clean_new_password2(self): + password1 = self.data.get("new_password1") + password2 = self.data.get("new_password2") + if password1 and password2 and password1 != password2: + raise ValidationError(_("passwords do not match")) + password_validation.validate_password(password2) + + return password2 + + def clean_email(self): + user_email = self.cleaned_data.get("email") + if not BlogUser.objects.filter( + email=user_email + ).exists(): + # todo 这里的报错提示可以判断一个邮箱是不是注册过,如果不想暴露可以修改 + raise ValidationError(_("email does not exist")) + return user_email + + def clean_code(self): + code = self.cleaned_data.get("code") + error = utils.verify( + email=self.cleaned_data.get("email"), + code=code, + ) + if error: + raise ValidationError(error) + return code + + +class ForgetPasswordCodeForm(forms.Form): + email = forms.EmailField( + label=_('Email'), + ) diff --git a/accounts/migrations/0001_initial.py b/accounts/migrations/0001_initial.py new file mode 100644 index 0000000..d2fbcab --- /dev/null +++ b/accounts/migrations/0001_initial.py @@ -0,0 +1,49 @@ +# Generated by Django 4.1.7 on 2023-03-02 07:14 + +import django.contrib.auth.models +import django.contrib.auth.validators +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('auth', '0012_alter_user_first_name_max_length'), + ] + + operations = [ + migrations.CreateModel( + name='BlogUser', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('password', models.CharField(max_length=128, verbose_name='password')), + ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), + ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), + ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')), + ('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')), + ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), + ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')), + ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), + ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), + ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), + ('nickname', models.CharField(blank=True, max_length=100, verbose_name='昵称')), + ('created_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='创建时间')), + ('last_mod_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='修改时间')), + ('source', models.CharField(blank=True, max_length=100, verbose_name='创建来源')), + ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')), + ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')), + ], + options={ + 'verbose_name': '用户', + 'verbose_name_plural': '用户', + 'ordering': ['-id'], + 'get_latest_by': 'id', + }, + managers=[ + ('objects', django.contrib.auth.models.UserManager()), + ], + ), + ] diff --git a/accounts/migrations/0002_alter_bloguser_options_remove_bloguser_created_time_and_more.py b/accounts/migrations/0002_alter_bloguser_options_remove_bloguser_created_time_and_more.py new file mode 100644 index 0000000..1a9f509 --- /dev/null +++ b/accounts/migrations/0002_alter_bloguser_options_remove_bloguser_created_time_and_more.py @@ -0,0 +1,46 @@ +# Generated by Django 4.2.5 on 2023-09-06 13:13 + +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('accounts', '0001_initial'), + ] + + operations = [ + migrations.AlterModelOptions( + name='bloguser', + options={'get_latest_by': 'id', 'ordering': ['-id'], 'verbose_name': 'user', 'verbose_name_plural': 'user'}, + ), + migrations.RemoveField( + model_name='bloguser', + name='created_time', + ), + migrations.RemoveField( + model_name='bloguser', + name='last_mod_time', + ), + migrations.AddField( + model_name='bloguser', + name='creation_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='creation time'), + ), + migrations.AddField( + model_name='bloguser', + name='last_modify_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='last modify time'), + ), + migrations.AlterField( + model_name='bloguser', + name='nickname', + field=models.CharField(blank=True, max_length=100, verbose_name='nick name'), + ), + migrations.AlterField( + model_name='bloguser', + name='source', + field=models.CharField(blank=True, max_length=100, verbose_name='create source'), + ), + ] diff --git a/accounts/migrations/__init__.py b/accounts/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/accounts/models.py b/accounts/models.py new file mode 100644 index 0000000..3baddbb --- /dev/null +++ b/accounts/models.py @@ -0,0 +1,35 @@ +from django.contrib.auth.models import AbstractUser +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 + + +# Create your models here. + +class BlogUser(AbstractUser): + nickname = models.CharField(_('nick name'), max_length=100, blank=True) + creation_time = models.DateTimeField(_('creation time'), default=now) + last_modify_time = models.DateTimeField(_('last modify time'), default=now) + source = models.CharField(_('create source'), max_length=100, blank=True) + + def get_absolute_url(self): + return reverse( + 'blog:author_detail', kwargs={ + 'author_name': self.username}) + + def __str__(self): + return self.email + + def get_full_url(self): + site = get_current_site().domain + url = "https://{site}{path}".format(site=site, + path=self.get_absolute_url()) + return url + + class Meta: + ordering = ['-id'] + verbose_name = _('user') + verbose_name_plural = verbose_name + get_latest_by = 'id' diff --git a/accounts/templatetags/__init__.py b/accounts/templatetags/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/accounts/tests.py b/accounts/tests.py new file mode 100644 index 0000000..6893411 --- /dev/null +++ b/accounts/tests.py @@ -0,0 +1,207 @@ +from django.test import Client, RequestFactory, TestCase +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 + + +# Create your tests here. + +class AccountTest(TestCase): + def setUp(self): + self.client = Client() + self.factory = RequestFactory() + self.blog_user = BlogUser.objects.create_user( + username="test", + email="admin@admin.com", + password="12345678" + ) + self.new_test = "xxx123--=" + + def test_validate_account(self): + site = get_current_site().domain + user = BlogUser.objects.create_superuser( + email="liangliangyy1@gmail.com", + username="liangliangyy1", + password="qwer!@#$ggg") + testuser = BlogUser.objects.get(username='liangliangyy1') + + loginresult = self.client.login( + username='liangliangyy1', + password='qwer!@#$ggg') + self.assertEqual(loginresult, True) + response = self.client.get('/admin/') + self.assertEqual(response.status_code, 200) + + category = Category() + category.name = "categoryaaa" + category.creation_time = timezone.now() + category.last_modify_time = timezone.now() + category.save() + + article = Article() + article.title = "nicetitleaaa" + article.body = "nicecontentaaa" + article.author = user + article.category = category + article.type = 'a' + article.status = 'p' + article.save() + + response = self.client.get(article.get_admin_url()) + self.assertEqual(response.status_code, 200) + + def test_validate_register(self): + self.assertEquals( + 0, len( + BlogUser.objects.filter( + email='user123@user.com'))) + response = self.client.post(reverse('account:register'), { + 'username': 'user1233', + 'email': 'user123@user.com', + 'password1': 'password123!q@wE#R$T', + 'password2': 'password123!q@wE#R$T', + }) + self.assertEquals( + 1, len( + BlogUser.objects.filter( + email='user123@user.com'))) + user = BlogUser.objects.filter(email='user123@user.com')[0] + sign = get_sha256(get_sha256(settings.SECRET_KEY + str(user.id))) + path = reverse('accounts:result') + url = '{path}?type=validation&id={id}&sign={sign}'.format( + path=path, id=user.id, sign=sign) + response = self.client.get(url) + self.assertEqual(response.status_code, 200) + + self.client.login(username='user1233', password='password123!q@wE#R$T') + user = BlogUser.objects.filter(email='user123@user.com')[0] + user.is_superuser = True + user.is_staff = True + user.save() + delete_sidebar_cache() + category = Category() + category.name = "categoryaaa" + category.creation_time = timezone.now() + category.last_modify_time = timezone.now() + category.save() + + article = Article() + article.category = category + article.title = "nicetitle333" + article.body = "nicecontentttt" + article.author = user + + article.type = 'a' + article.status = 'p' + article.save() + + response = self.client.get(article.get_admin_url()) + self.assertEqual(response.status_code, 200) + + response = self.client.get(reverse('account:logout')) + self.assertIn(response.status_code, [301, 302, 200]) + + response = self.client.get(article.get_admin_url()) + self.assertIn(response.status_code, [301, 302, 200]) + + response = self.client.post(reverse('account:login'), { + 'username': 'user1233', + 'password': 'password123' + }) + self.assertIn(response.status_code, [301, 302, 200]) + + response = self.client.get(article.get_admin_url()) + self.assertIn(response.status_code, [301, 302, 200]) + + def test_verify_email_code(self): + to_email = "admin@admin.com" + code = generate_code() + utils.set_code(to_email, code) + utils.send_verify_email(to_email, code) + + err = utils.verify("admin@admin.com", code) + self.assertEqual(err, None) + + err = utils.verify("admin@123.com", code) + self.assertEqual(type(err), str) + + def test_forget_password_email_code_success(self): + resp = self.client.post( + path=reverse("account:forget_password_code"), + data=dict(email="admin@admin.com") + ) + + self.assertEqual(resp.status_code, 200) + self.assertEqual(resp.content.decode("utf-8"), "ok") + + def test_forget_password_email_code_fail(self): + resp = self.client.post( + path=reverse("account:forget_password_code"), + data=dict() + ) + self.assertEqual(resp.content.decode("utf-8"), "错误的邮箱") + + resp = self.client.post( + path=reverse("account:forget_password_code"), + data=dict(email="admin@com") + ) + self.assertEqual(resp.content.decode("utf-8"), "错误的邮箱") + + def test_forget_password_email_success(self): + code = generate_code() + utils.set_code(self.blog_user.email, code) + data = dict( + new_password1=self.new_test, + new_password2=self.new_test, + email=self.blog_user.email, + code=code, + ) + resp = self.client.post( + path=reverse("account:forget_password"), + data=data + ) + self.assertEqual(resp.status_code, 302) + + # 验证用户密码是否修改成功 + blog_user = BlogUser.objects.filter( + email=self.blog_user.email, + ).first() # type: BlogUser + self.assertNotEqual(blog_user, None) + self.assertEqual(blog_user.check_password(data["new_password1"]), True) + + def test_forget_password_email_not_user(self): + data = dict( + new_password1=self.new_test, + new_password2=self.new_test, + email="123@123.com", + code="123456", + ) + resp = self.client.post( + path=reverse("account:forget_password"), + data=data + ) + + self.assertEqual(resp.status_code, 200) + + + def test_forget_password_email_code_error(self): + code = generate_code() + utils.set_code(self.blog_user.email, code) + data = dict( + new_password1=self.new_test, + new_password2=self.new_test, + email=self.blog_user.email, + code="111111", + ) + resp = self.client.post( + path=reverse("account:forget_password"), + data=data + ) + + self.assertEqual(resp.status_code, 200) + diff --git a/accounts/urls.py b/accounts/urls.py new file mode 100644 index 0000000..107a801 --- /dev/null +++ b/accounts/urls.py @@ -0,0 +1,28 @@ +from django.urls import path +from django.urls import re_path + +from . import views +from .forms import LoginForm + +app_name = "accounts" + +urlpatterns = [re_path(r'^login/$', + views.LoginView.as_view(success_url='/'), + name='login', + kwargs={'authentication_form': LoginForm}), + re_path(r'^register/$', + views.RegisterView.as_view(success_url="/"), + name='register'), + re_path(r'^logout/$', + views.LogoutView.as_view(), + name='logout'), + path(r'account/result.html', + views.account_result, + name='result'), + re_path(r'^forget_password/$', + views.ForgetPasswordView.as_view(), + name='forget_password'), + re_path(r'^forget_password_code/$', + views.ForgetPasswordEmailCode.as_view(), + name='forget_password_code'), + ] diff --git a/accounts/user_login_backend.py b/accounts/user_login_backend.py new file mode 100644 index 0000000..73cdca1 --- /dev/null +++ b/accounts/user_login_backend.py @@ -0,0 +1,26 @@ +from django.contrib.auth import get_user_model +from django.contrib.auth.backends import ModelBackend + + +class EmailOrUsernameModelBackend(ModelBackend): + """ + 允许使用用户名或邮箱登录 + """ + + def authenticate(self, request, username=None, password=None, **kwargs): + if '@' in username: + kwargs = {'email': username} + else: + kwargs = {'username': username} + try: + user = get_user_model().objects.get(**kwargs) + if user.check_password(password): + return user + except get_user_model().DoesNotExist: + return None + + def get_user(self, username): + try: + return get_user_model().objects.get(pk=username) + except get_user_model().DoesNotExist: + return None diff --git a/accounts/utils.py b/accounts/utils.py new file mode 100644 index 0000000..4b94bdf --- /dev/null +++ b/accounts/utils.py @@ -0,0 +1,49 @@ +import typing +from datetime import timedelta + +from django.core.cache import cache +from django.utils.translation import gettext +from django.utils.translation import gettext_lazy as _ + +from djangoblog.utils import send_email + +_code_ttl = timedelta(minutes=5) + + +def send_verify_email(to_mail: str, code: str, subject: str = _("Verify Email")): + """发送重设密码验证码 + Args: + to_mail: 接受邮箱 + subject: 邮件主题 + code: 验证码 + """ + html_content = _( + "You are resetting the password, the verification code is:%(code)s, valid within 5 minutes, please keep it " + "properly") % {'code': code} + send_email([to_mail], subject, html_content) + + +def verify(email: str, code: str) -> typing.Optional[str]: + """验证code是否有效 + Args: + email: 请求邮箱 + code: 验证码 + Return: + 如果有错误就返回错误str + Node: + 这里的错误处理不太合理,应该采用raise抛出 + 否测调用方也需要对error进行处理 + """ + cache_code = get_code(email) + if cache_code != code: + return gettext("Verification code error") + + +def set_code(email: str, code: str): + """设置code""" + cache.set(email, code, _code_ttl.seconds) + + +def get_code(email: str) -> typing.Optional[str]: + """获取code""" + return cache.get(email) diff --git a/accounts/views.py b/accounts/views.py new file mode 100644 index 0000000..ae67aec --- /dev/null +++ b/accounts/views.py @@ -0,0 +1,204 @@ +import logging +from django.utils.translation import gettext_lazy as _ +from django.conf import settings +from django.contrib import auth +from django.contrib.auth import REDIRECT_FIELD_NAME +from django.contrib.auth import get_user_model +from django.contrib.auth import logout +from django.contrib.auth.forms import AuthenticationForm +from django.contrib.auth.hashers import make_password +from django.http import HttpResponseRedirect, HttpResponseForbidden +from django.http.request import HttpRequest +from django.http.response import HttpResponse +from django.shortcuts import get_object_or_404 +from django.shortcuts import render +from django.urls import reverse +from django.utils.decorators import method_decorator +from django.utils.http import url_has_allowed_host_and_scheme +from django.views import View +from django.views.decorators.cache import never_cache +from django.views.decorators.csrf import csrf_protect +from django.views.decorators.debug import sensitive_post_parameters +from django.views.generic import FormView, RedirectView + +from djangoblog.utils import send_email, get_sha256, get_current_site, generate_code, delete_sidebar_cache +from . import utils +from .forms import RegisterForm, LoginForm, ForgetPasswordForm, ForgetPasswordCodeForm +from .models import BlogUser + +logger = logging.getLogger(__name__) + + +# Create your views here. + +class RegisterView(FormView): + form_class = RegisterForm + template_name = 'account/registration_form.html' + + @method_decorator(csrf_protect) + def dispatch(self, *args, **kwargs): + return super(RegisterView, self).dispatch(*args, **kwargs) + + def form_valid(self, form): + if form.is_valid(): + user = form.save(False) + user.is_active = False + user.source = 'Register' + user.save(True) + site = get_current_site().domain + sign = get_sha256(get_sha256(settings.SECRET_KEY + str(user.id))) + + if settings.DEBUG: + site = '127.0.0.1:8000' + path = reverse('account:result') + url = "http://{site}{path}?type=validation&id={id}&sign={sign}".format( + site=site, path=path, id=user.id, sign=sign) + + content = """ +

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

+ + {url} + + 再次感谢您! +
+ 如果上面链接无法打开,请将此链接复制至浏览器。 + {url} + """.format(url=url) + send_email( + emailto=[ + user.email, + ], + title='验证您的电子邮箱', + content=content) + + url = reverse('accounts:result') + \ + '?type=register&id=' + str(user.id) + return HttpResponseRedirect(url) + else: + return self.render_to_response({ + 'form': form + }) + + +class LogoutView(RedirectView): + url = '/login/' + + @method_decorator(never_cache) + def dispatch(self, request, *args, **kwargs): + return super(LogoutView, self).dispatch(request, *args, **kwargs) + + def get(self, request, *args, **kwargs): + logout(request) + delete_sidebar_cache() + return super(LogoutView, self).get(request, *args, **kwargs) + + +class LoginView(FormView): + form_class = LoginForm + template_name = 'account/login.html' + success_url = '/' + redirect_field_name = REDIRECT_FIELD_NAME + login_ttl = 2626560 # 一个月的时间 + + @method_decorator(sensitive_post_parameters('password')) + @method_decorator(csrf_protect) + @method_decorator(never_cache) + def dispatch(self, request, *args, **kwargs): + + return super(LoginView, self).dispatch(request, *args, **kwargs) + + def get_context_data(self, **kwargs): + redirect_to = self.request.GET.get(self.redirect_field_name) + if redirect_to is None: + redirect_to = '/' + kwargs['redirect_to'] = redirect_to + + return super(LoginView, self).get_context_data(**kwargs) + + def form_valid(self, form): + form = AuthenticationForm(data=self.request.POST, request=self.request) + + if form.is_valid(): + delete_sidebar_cache() + logger.info(self.redirect_field_name) + + auth.login(self.request, form.get_user()) + if self.request.POST.get("remember"): + self.request.session.set_expiry(self.login_ttl) + return super(LoginView, self).form_valid(form) + # return HttpResponseRedirect('/') + else: + return self.render_to_response({ + 'form': form + }) + + def get_success_url(self): + + redirect_to = self.request.POST.get(self.redirect_field_name) + if not url_has_allowed_host_and_scheme( + url=redirect_to, allowed_hosts=[ + self.request.get_host()]): + redirect_to = self.success_url + return redirect_to + + +def account_result(request): + type = request.GET.get('type') + id = request.GET.get('id') + + user = get_object_or_404(get_user_model(), id=id) + logger.info(type) + if user.is_active: + return HttpResponseRedirect('/') + if type and type in ['register', 'validation']: + if type == 'register': + content = ''' + 恭喜您注册成功,一封验证邮件已经发送到您的邮箱,请验证您的邮箱后登录本站。 + ''' + title = '注册成功' + else: + c_sign = get_sha256(get_sha256(settings.SECRET_KEY + str(user.id))) + sign = request.GET.get('sign') + if sign != c_sign: + return HttpResponseForbidden() + user.is_active = True + user.save() + content = ''' + 恭喜您已经成功的完成邮箱验证,您现在可以使用您的账号来登录本站。 + ''' + title = '验证成功' + return render(request, 'account/result.html', { + 'title': title, + 'content': content + }) + else: + return HttpResponseRedirect('/') + + +class ForgetPasswordView(FormView): + form_class = ForgetPasswordForm + template_name = 'account/forget_password.html' + + def form_valid(self, form): + if form.is_valid(): + blog_user = BlogUser.objects.filter(email=form.cleaned_data.get("email")).get() + blog_user.password = make_password(form.cleaned_data["new_password2"]) + blog_user.save() + return HttpResponseRedirect('/login/') + else: + return self.render_to_response({'form': form}) + + +class ForgetPasswordEmailCode(View): + + def post(self, request: HttpRequest): + form = ForgetPasswordCodeForm(request.POST) + if not form.is_valid(): + return HttpResponse("错误的邮箱") + to_email = form.cleaned_data["email"] + + code = generate_code() + utils.send_verify_email(to_email, code) + utils.set_code(to_email, code) + + return HttpResponse("ok") diff --git a/blog/__init__.py b/blog/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/blog/admin.py b/blog/admin.py new file mode 100644 index 0000000..46c3420 --- /dev/null +++ b/blog/admin.py @@ -0,0 +1,112 @@ +from django import forms +from django.contrib import admin +from django.contrib.auth import get_user_model +from django.urls import reverse +from django.utils.html import format_html +from django.utils.translation import gettext_lazy as _ + +# Register your models here. +from .models import Article + + +class ArticleForm(forms.ModelForm): + # body = forms.CharField(widget=AdminPagedownWidget()) + + class Meta: + model = Article + fields = '__all__' + + +def makr_article_publish(modeladmin, request, queryset): + queryset.update(status='p') + + +def draft_article(modeladmin, request, queryset): + queryset.update(status='d') + + +def close_article_commentstatus(modeladmin, request, queryset): + queryset.update(comment_status='c') + + +def open_article_commentstatus(modeladmin, request, queryset): + queryset.update(comment_status='o') + + +makr_article_publish.short_description = _('Publish selected articles') +draft_article.short_description = _('Draft selected articles') +close_article_commentstatus.short_description = _('Close article comments') +open_article_commentstatus.short_description = _('Open article comments') + + +class ArticlelAdmin(admin.ModelAdmin): + list_per_page = 20 + search_fields = ('body', 'title') + form = ArticleForm + list_display = ( + 'id', + 'title', + 'author', + 'link_to_category', + 'creation_time', + 'views', + 'status', + 'type', + 'article_order') + list_display_links = ('id', 'title') + list_filter = ('status', 'type', 'category') + filter_horizontal = ('tags',) + exclude = ('creation_time', 'last_modify_time') + view_on_site = True + actions = [ + makr_article_publish, + draft_article, + close_article_commentstatus, + open_article_commentstatus] + + def link_to_category(self, obj): + info = (obj.category._meta.app_label, obj.category._meta.model_name) + link = reverse('admin:%s_%s_change' % info, args=(obj.category.id,)) + return format_html(u'%s' % (link, obj.category.name)) + + link_to_category.short_description = _('category') + + def get_form(self, request, obj=None, **kwargs): + form = super(ArticlelAdmin, self).get_form(request, obj, **kwargs) + form.base_fields['author'].queryset = get_user_model( + ).objects.filter(is_superuser=True) + return form + + def save_model(self, request, obj, form, change): + super(ArticlelAdmin, self).save_model(request, obj, form, change) + + def get_view_on_site_url(self, obj=None): + if obj: + url = obj.get_full_url() + return url + else: + from djangoblog.utils import get_current_site + site = get_current_site().domain + return site + + +class TagAdmin(admin.ModelAdmin): + exclude = ('slug', 'last_mod_time', 'creation_time') + + +class CategoryAdmin(admin.ModelAdmin): + list_display = ('name', 'parent_category', 'index') + exclude = ('slug', 'last_mod_time', 'creation_time') + + +class LinksAdmin(admin.ModelAdmin): + exclude = ('last_mod_time', 'creation_time') + + +class SideBarAdmin(admin.ModelAdmin): + list_display = ('name', 'content', 'is_enable', 'sequence') + exclude = ('last_mod_time', 'creation_time') + + +class BlogSettingsAdmin(admin.ModelAdmin): + pass diff --git a/blog/apps.py b/blog/apps.py new file mode 100644 index 0000000..7930587 --- /dev/null +++ b/blog/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class BlogConfig(AppConfig): + name = 'blog' diff --git a/blog/context_processors.py b/blog/context_processors.py new file mode 100644 index 0000000..73e3088 --- /dev/null +++ b/blog/context_processors.py @@ -0,0 +1,43 @@ +import logging + +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): + 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, + 'SITE_SEO_DESCRIPTION': setting.site_seo_description, + 'SITE_DESCRIPTION': setting.site_description, + 'SITE_KEYWORDS': setting.site_keywords, + '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', + status='p'), + 'OPEN_SITE_COMMENT': setting.open_site_comment, + 'BEIAN_CODE': setting.beian_code, + 'ANALYTICS_CODE': setting.analytics_code, + "BEIAN_CODE_GONGAN": setting.gongan_beiancode, + "SHOW_GONGAN_CODE": setting.show_gongan_code, + "CURRENT_YEAR": timezone.now().year, + "GLOBAL_HEADER": setting.global_header, + "GLOBAL_FOOTER": setting.global_footer, + "COMMENT_NEED_REVIEW": setting.comment_need_review, + } + cache.set(key, value, 60 * 60 * 10) + return value diff --git a/blog/documents.py b/blog/documents.py new file mode 100644 index 0000000..0f1db7b --- /dev/null +++ b/blog/documents.py @@ -0,0 +1,213 @@ +import time + +import elasticsearch.client +from django.conf import settings +from elasticsearch_dsl import Document, InnerDoc, Date, Integer, Long, Text, Object, GeoPoint, Keyword, Boolean +from elasticsearch_dsl.connections import connections + +from blog.models import Article + +ELASTICSEARCH_ENABLED = hasattr(settings, 'ELASTICSEARCH_DSL') + +if ELASTICSEARCH_ENABLED: + connections.create_connection( + hosts=[settings.ELASTICSEARCH_DSL['default']['hosts']]) + from elasticsearch import Elasticsearch + + es = Elasticsearch(settings.ELASTICSEARCH_DSL['default']['hosts']) + from elasticsearch.client import IngestClient + + c = IngestClient(es) + try: + c.get_pipeline('geoip') + except elasticsearch.exceptions.NotFoundError: + c.put_pipeline('geoip', body='''{ + "description" : "Add geoip info", + "processors" : [ + { + "geoip" : { + "field" : "ip" + } + } + ] + }''') + + +class GeoIp(InnerDoc): + continent_name = Keyword() + country_iso_code = Keyword() + country_name = Keyword() + location = GeoPoint() + + +class UserAgentBrowser(InnerDoc): + Family = Keyword() + Version = Keyword() + + +class UserAgentOS(UserAgentBrowser): + pass + + +class UserAgentDevice(InnerDoc): + Family = Keyword() + Brand = Keyword() + Model = Keyword() + + +class UserAgent(InnerDoc): + browser = Object(UserAgentBrowser, required=False) + os = Object(UserAgentOS, required=False) + device = Object(UserAgentDevice, required=False) + string = Text() + is_bot = Boolean() + + +class ElapsedTimeDocument(Document): + url = Keyword() + time_taken = Long() + log_datetime = Date() + ip = Keyword() + geoip = Object(GeoIp, required=False) + useragent = Object(UserAgent, required=False) + + class Index: + name = 'performance' + settings = { + "number_of_shards": 1, + "number_of_replicas": 0 + } + + class Meta: + doc_type = 'ElapsedTime' + + +class ElaspedTimeDocumentManager: + @staticmethod + def build_index(): + from elasticsearch import Elasticsearch + client = Elasticsearch(settings.ELASTICSEARCH_DSL['default']['hosts']) + res = client.indices.exists(index="performance") + if not res: + ElapsedTimeDocument.init() + + @staticmethod + def delete_index(): + from elasticsearch import Elasticsearch + es = Elasticsearch(settings.ELASTICSEARCH_DSL['default']['hosts']) + es.indices.delete(index='performance', ignore=[400, 404]) + + @staticmethod + def create(url, time_taken, log_datetime, useragent, ip): + ElaspedTimeDocumentManager.build_index() + ua = UserAgent() + ua.browser = UserAgentBrowser() + ua.browser.Family = useragent.browser.family + ua.browser.Version = useragent.browser.version_string + + ua.os = UserAgentOS() + ua.os.Family = useragent.os.family + ua.os.Version = useragent.os.version_string + + ua.device = UserAgentDevice() + ua.device.Family = useragent.device.family + ua.device.Brand = useragent.device.brand + ua.device.Model = useragent.device.model + ua.string = useragent.ua_string + ua.is_bot = useragent.is_bot + + doc = ElapsedTimeDocument( + meta={ + 'id': int( + round( + time.time() * + 1000)) + }, + url=url, + time_taken=time_taken, + log_datetime=log_datetime, + useragent=ua, ip=ip) + doc.save(pipeline="geoip") + + +class ArticleDocument(Document): + body = Text(analyzer='ik_max_word', search_analyzer='ik_smart') + title = Text(analyzer='ik_max_word', search_analyzer='ik_smart') + author = Object(properties={ + 'nickname': Text(analyzer='ik_max_word', search_analyzer='ik_smart'), + 'id': Integer() + }) + category = Object(properties={ + 'name': Text(analyzer='ik_max_word', search_analyzer='ik_smart'), + 'id': Integer() + }) + tags = Object(properties={ + 'name': Text(analyzer='ik_max_word', search_analyzer='ik_smart'), + 'id': Integer() + }) + + pub_time = Date() + status = Text() + comment_status = Text() + type = Text() + views = Integer() + article_order = Integer() + + class Index: + name = 'blog' + settings = { + "number_of_shards": 1, + "number_of_replicas": 0 + } + + class Meta: + doc_type = 'Article' + + +class ArticleDocumentManager(): + + def __init__(self): + self.create_index() + + def create_index(self): + ArticleDocument.init() + + def delete_index(self): + from elasticsearch import Elasticsearch + es = Elasticsearch(settings.ELASTICSEARCH_DSL['default']['hosts']) + es.indices.delete(index='blog', ignore=[400, 404]) + + def convert_to_doc(self, articles): + return [ + ArticleDocument( + meta={ + 'id': article.id}, + body=article.body, + title=article.title, + author={ + 'nickname': article.author.username, + 'id': article.author.id}, + category={ + 'name': article.category.name, + 'id': article.category.id}, + tags=[ + { + 'name': t.name, + 'id': t.id} for t in article.tags.all()], + pub_time=article.pub_time, + status=article.status, + comment_status=article.comment_status, + type=article.type, + views=article.views, + article_order=article.article_order) for article in articles] + + def rebuild(self, articles=None): + ArticleDocument.init() + articles = articles if articles else Article.objects.all() + docs = self.convert_to_doc(articles) + for doc in docs: + doc.save() + + def update_docs(self, docs): + for doc in docs: + doc.save() diff --git a/blog/forms.py b/blog/forms.py new file mode 100644 index 0000000..715be76 --- /dev/null +++ b/blog/forms.py @@ -0,0 +1,19 @@ +import logging + +from django import forms +from haystack.forms import SearchForm + +logger = logging.getLogger(__name__) + + +class BlogSearchForm(SearchForm): + querydata = forms.CharField(required=True) + + def search(self): + datas = super(BlogSearchForm, self).search() + if not self.is_valid(): + return self.no_query_found() + + if self.cleaned_data['querydata']: + logger.info(self.cleaned_data['querydata']) + return datas diff --git a/blog/management/__init__.py b/blog/management/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/blog/management/commands/__init__.py b/blog/management/commands/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/blog/management/commands/build_index.py b/blog/management/commands/build_index.py new file mode 100644 index 0000000..3c4acd7 --- /dev/null +++ b/blog/management/commands/build_index.py @@ -0,0 +1,18 @@ +from django.core.management.base import BaseCommand + +from blog.documents import ElapsedTimeDocument, ArticleDocumentManager, ElaspedTimeDocumentManager, \ + ELASTICSEARCH_ENABLED + + +# TODO 参数化 +class Command(BaseCommand): + help = 'build search index' + + def handle(self, *args, **options): + if ELASTICSEARCH_ENABLED: + ElaspedTimeDocumentManager.build_index() + manager = ElapsedTimeDocument() + manager.init() + manager = ArticleDocumentManager() + manager.delete_index() + manager.rebuild() diff --git a/blog/management/commands/build_search_words.py b/blog/management/commands/build_search_words.py new file mode 100644 index 0000000..cfe7e0d --- /dev/null +++ b/blog/management/commands/build_search_words.py @@ -0,0 +1,13 @@ +from django.core.management.base import BaseCommand + +from blog.models import Tag, Category + + +# TODO 参数化 +class Command(BaseCommand): + help = 'build search words' + + def handle(self, *args, **options): + datas = set([t.name for t in Tag.objects.all()] + + [t.name for t in Category.objects.all()]) + print('\n'.join(datas)) diff --git a/blog/management/commands/clear_cache.py b/blog/management/commands/clear_cache.py new file mode 100644 index 0000000..0d66172 --- /dev/null +++ b/blog/management/commands/clear_cache.py @@ -0,0 +1,11 @@ +from django.core.management.base import BaseCommand + +from djangoblog.utils import cache + + +class Command(BaseCommand): + help = 'clear the whole cache' + + def handle(self, *args, **options): + cache.clear() + self.stdout.write(self.style.SUCCESS('Cleared cache\n')) diff --git a/blog/management/commands/create_testdata.py b/blog/management/commands/create_testdata.py new file mode 100644 index 0000000..675d2ba --- /dev/null +++ b/blog/management/commands/create_testdata.py @@ -0,0 +1,40 @@ +from django.contrib.auth import get_user_model +from django.contrib.auth.hashers import make_password +from django.core.management.base import BaseCommand + +from blog.models import Article, Tag, Category + + +class Command(BaseCommand): + help = 'create test datas' + + def handle(self, *args, **options): + user = get_user_model().objects.get_or_create( + email='test@test.com', username='测试用户', password=make_password('test!q@w#eTYU'))[0] + + pcategory = Category.objects.get_or_create( + name='我是父类目', parent_category=None)[0] + + category = Category.objects.get_or_create( + name='子类目', parent_category=pcategory)[0] + + category.save() + basetag = Tag() + basetag.name = "标签" + basetag.save() + for i in range(1, 20): + article = Article.objects.get_or_create( + category=category, + title='nice title ' + str(i), + body='nice content ' + str(i), + author=user)[0] + tag = Tag() + tag.name = "标签" + str(i) + tag.save() + article.tags.add(tag) + article.tags.add(basetag) + article.save() + + from djangoblog.utils import cache + cache.clear() + self.stdout.write(self.style.SUCCESS('created test datas \n')) diff --git a/blog/management/commands/ping_baidu.py b/blog/management/commands/ping_baidu.py new file mode 100644 index 0000000..2c7fbdd --- /dev/null +++ b/blog/management/commands/ping_baidu.py @@ -0,0 +1,50 @@ +from django.core.management.base import BaseCommand + +from djangoblog.spider_notify import SpiderNotify +from djangoblog.utils import get_current_site +from blog.models import Article, Tag, Category + +site = get_current_site().domain + + +class Command(BaseCommand): + help = 'notify baidu url' + + def add_arguments(self, parser): + parser.add_argument( + 'data_type', + type=str, + choices=[ + 'all', + 'article', + 'tag', + 'category'], + help='article : all article,tag : all tag,category: all category,all: All of these') + + def get_full_url(self, path): + url = "https://{site}{path}".format(site=site, path=path) + return url + + def handle(self, *args, **options): + type = options['data_type'] + self.stdout.write('start get %s' % type) + + urls = [] + if type == 'article' or type == 'all': + for article in Article.objects.filter(status='p'): + urls.append(article.get_full_url()) + if type == 'tag' or type == 'all': + for tag in Tag.objects.all(): + url = tag.get_absolute_url() + urls.append(self.get_full_url(url)) + if type == 'category' or type == 'all': + for category in Category.objects.all(): + url = category.get_absolute_url() + urls.append(self.get_full_url(url)) + + self.stdout.write( + self.style.SUCCESS( + 'start notify %d urls' % + len(urls))) + SpiderNotify.baidu_notify(urls) + self.stdout.write(self.style.SUCCESS('finish notify')) diff --git a/blog/management/commands/sync_user_avatar.py b/blog/management/commands/sync_user_avatar.py new file mode 100644 index 0000000..d0f4612 --- /dev/null +++ b/blog/management/commands/sync_user_avatar.py @@ -0,0 +1,47 @@ +import requests +from django.core.management.base import BaseCommand +from django.templatetags.static import static + +from djangoblog.utils import save_user_avatar +from oauth.models import OAuthUser +from oauth.oauthmanager import get_manager_by_type + + +class Command(BaseCommand): + help = 'sync user avatar' + + def test_picture(self, url): + try: + if requests.get(url, timeout=2).status_code == 200: + return True + except: + pass + + def handle(self, *args, **options): + static_url = static("../") + users = OAuthUser.objects.all() + self.stdout.write(f'开始同步{len(users)}个用户头像') + for u in users: + self.stdout.write(f'开始同步:{u.nickname}') + url = u.picture + if url: + if url.startswith(static_url): + if self.test_picture(url): + continue + else: + if u.metadata: + manage = get_manager_by_type(u.type) + url = manage.get_picture(u.metadata) + url = save_user_avatar(url) + else: + url = static('blog/img/avatar.png') + else: + url = save_user_avatar(url) + else: + url = static('blog/img/avatar.png') + if url: + self.stdout.write( + f'结束同步:{u.nickname}.url:{url}') + u.picture = url + u.save() + self.stdout.write('结束同步') diff --git a/blog/middleware.py b/blog/middleware.py new file mode 100644 index 0000000..94dd70c --- /dev/null +++ b/blog/middleware.py @@ -0,0 +1,42 @@ +import logging +import time + +from ipware import get_client_ip +from user_agents import parse + +from blog.documents import ELASTICSEARCH_ENABLED, ElaspedTimeDocumentManager + +logger = logging.getLogger(__name__) + + +class OnlineMiddleware(object): + def __init__(self, get_response=None): + self.get_response = get_response + super().__init__() + + def __call__(self, request): + ''' page render time ''' + start_time = time.time() + response = self.get_response(request) + http_user_agent = request.META.get('HTTP_USER_AGENT', '') + ip, _ = get_client_ip(request) + user_agent = parse(http_user_agent) + if not response.streaming: + try: + cast_time = time.time() - start_time + if ELASTICSEARCH_ENABLED: + time_taken = round((cast_time) * 1000, 2) + url = request.path + from django.utils import timezone + ElaspedTimeDocumentManager.create( + url=url, + time_taken=time_taken, + log_datetime=timezone.now(), + useragent=user_agent, + ip=ip) + response.content = response.content.replace( + b'', str.encode(str(cast_time)[:5])) + except Exception as e: + logger.error("Error OnlineMiddleware: %s" % e) + + return response diff --git a/blog/migrations/0001_initial.py b/blog/migrations/0001_initial.py new file mode 100644 index 0000000..3d391b6 --- /dev/null +++ b/blog/migrations/0001_initial.py @@ -0,0 +1,137 @@ +# Generated by Django 4.1.7 on 2023-03-02 07:14 + +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): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='BlogSettings', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('sitename', models.CharField(default='', max_length=200, verbose_name='网站名称')), + ('site_description', models.TextField(default='', max_length=1000, verbose_name='网站描述')), + ('site_seo_description', models.TextField(default='', max_length=1000, verbose_name='网站SEO描述')), + ('site_keywords', models.TextField(default='', max_length=1000, verbose_name='网站关键字')), + ('article_sub_length', models.IntegerField(default=300, verbose_name='文章摘要长度')), + ('sidebar_article_count', models.IntegerField(default=10, verbose_name='侧边栏文章数目')), + ('sidebar_comment_count', models.IntegerField(default=5, verbose_name='侧边栏评论数目')), + ('article_comment_count', models.IntegerField(default=5, verbose_name='文章页面默认显示评论数目')), + ('show_google_adsense', models.BooleanField(default=False, verbose_name='是否显示谷歌广告')), + ('google_adsense_codes', models.TextField(blank=True, default='', max_length=2000, null=True, verbose_name='广告内容')), + ('open_site_comment', models.BooleanField(default=True, verbose_name='是否打开网站评论功能')), + ('beiancode', models.CharField(blank=True, default='', max_length=2000, null=True, verbose_name='备案号')), + ('analyticscode', models.TextField(default='', max_length=1000, verbose_name='网站统计代码')), + ('show_gongan_code', models.BooleanField(default=False, verbose_name='是否显示公安备案号')), + ('gongan_beiancode', models.TextField(blank=True, default='', max_length=2000, null=True, verbose_name='公安备案号')), + ], + options={ + 'verbose_name': '网站配置', + 'verbose_name_plural': '网站配置', + }, + ), + migrations.CreateModel( + name='Links', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=30, unique=True, verbose_name='链接名称')), + ('link', models.URLField(verbose_name='链接地址')), + ('sequence', models.IntegerField(unique=True, verbose_name='排序')), + ('is_enable', models.BooleanField(default=True, verbose_name='是否显示')), + ('show_type', models.CharField(choices=[('i', '首页'), ('l', '列表页'), ('p', '文章页面'), ('a', '全站'), ('s', '友情链接页面')], default='i', max_length=1, verbose_name='显示类型')), + ('created_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='创建时间')), + ('last_mod_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='修改时间')), + ], + options={ + 'verbose_name': '友情链接', + 'verbose_name_plural': '友情链接', + 'ordering': ['sequence'], + }, + ), + migrations.CreateModel( + name='SideBar', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=100, verbose_name='标题')), + ('content', models.TextField(verbose_name='内容')), + ('sequence', models.IntegerField(unique=True, verbose_name='排序')), + ('is_enable', models.BooleanField(default=True, verbose_name='是否启用')), + ('created_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='创建时间')), + ('last_mod_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='修改时间')), + ], + options={ + 'verbose_name': '侧边栏', + 'verbose_name_plural': '侧边栏', + 'ordering': ['sequence'], + }, + ), + migrations.CreateModel( + name='Tag', + fields=[ + ('id', models.AutoField(primary_key=True, serialize=False)), + ('created_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='创建时间')), + ('last_mod_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='修改时间')), + ('name', models.CharField(max_length=30, unique=True, verbose_name='标签名')), + ('slug', models.SlugField(blank=True, default='no-slug', max_length=60)), + ], + options={ + 'verbose_name': '标签', + 'verbose_name_plural': '标签', + 'ordering': ['name'], + }, + ), + migrations.CreateModel( + name='Category', + fields=[ + ('id', models.AutoField(primary_key=True, serialize=False)), + ('created_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='创建时间')), + ('last_mod_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='修改时间')), + ('name', models.CharField(max_length=30, unique=True, verbose_name='分类名')), + ('slug', models.SlugField(blank=True, default='no-slug', max_length=60)), + ('index', models.IntegerField(default=0, verbose_name='权重排序-越大越靠前')), + ('parent_category', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='blog.category', verbose_name='父级分类')), + ], + options={ + 'verbose_name': '分类', + 'verbose_name_plural': '分类', + 'ordering': ['-index'], + }, + ), + migrations.CreateModel( + name='Article', + fields=[ + ('id', models.AutoField(primary_key=True, serialize=False)), + ('created_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='创建时间')), + ('last_mod_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='修改时间')), + ('title', models.CharField(max_length=200, unique=True, verbose_name='标题')), + ('body', mdeditor.fields.MDTextField(verbose_name='正文')), + ('pub_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='发布时间')), + ('status', models.CharField(choices=[('d', '草稿'), ('p', '发表')], default='p', max_length=1, verbose_name='文章状态')), + ('comment_status', models.CharField(choices=[('o', '打开'), ('c', '关闭')], default='o', max_length=1, verbose_name='评论状态')), + ('type', models.CharField(choices=[('a', '文章'), ('p', '页面')], default='a', max_length=1, verbose_name='类型')), + ('views', models.PositiveIntegerField(default=0, verbose_name='浏览量')), + ('article_order', models.IntegerField(default=0, verbose_name='排序,数字越大越靠前')), + ('show_toc', models.BooleanField(default=False, verbose_name='是否显示toc目录')), + ('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='作者')), + ('category', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='blog.category', verbose_name='分类')), + ('tags', models.ManyToManyField(blank=True, to='blog.tag', verbose_name='标签集合')), + ], + options={ + 'verbose_name': '文章', + 'verbose_name_plural': '文章', + 'ordering': ['-article_order', '-pub_time'], + 'get_latest_by': 'id', + }, + ), + ] diff --git a/blog/migrations/0002_blogsettings_global_footer_and_more.py b/blog/migrations/0002_blogsettings_global_footer_and_more.py new file mode 100644 index 0000000..adbaa36 --- /dev/null +++ b/blog/migrations/0002_blogsettings_global_footer_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 4.1.7 on 2023-03-29 06:08 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('blog', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='blogsettings', + name='global_footer', + field=models.TextField(blank=True, default='', null=True, verbose_name='公共尾部'), + ), + migrations.AddField( + model_name='blogsettings', + name='global_header', + field=models.TextField(blank=True, default='', null=True, verbose_name='公共头部'), + ), + ] diff --git a/blog/migrations/0003_blogsettings_comment_need_review.py b/blog/migrations/0003_blogsettings_comment_need_review.py new file mode 100644 index 0000000..e9f5502 --- /dev/null +++ b/blog/migrations/0003_blogsettings_comment_need_review.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2.1 on 2023-05-09 07:45 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ('blog', '0002_blogsettings_global_footer_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='blogsettings', + name='comment_need_review', + field=models.BooleanField(default=False, verbose_name='评论是否需要审核'), + ), + ] diff --git a/blog/migrations/0004_rename_analyticscode_blogsettings_analytics_code_and_more.py b/blog/migrations/0004_rename_analyticscode_blogsettings_analytics_code_and_more.py new file mode 100644 index 0000000..ceb1398 --- /dev/null +++ b/blog/migrations/0004_rename_analyticscode_blogsettings_analytics_code_and_more.py @@ -0,0 +1,27 @@ +# Generated by Django 4.2.1 on 2023-05-09 07:51 + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ('blog', '0003_blogsettings_comment_need_review'), + ] + + operations = [ + migrations.RenameField( + model_name='blogsettings', + old_name='analyticscode', + new_name='analytics_code', + ), + migrations.RenameField( + model_name='blogsettings', + old_name='beiancode', + new_name='beian_code', + ), + migrations.RenameField( + model_name='blogsettings', + old_name='sitename', + new_name='site_name', + ), + ] diff --git a/blog/migrations/0005_alter_article_options_alter_category_options_and_more.py b/blog/migrations/0005_alter_article_options_alter_category_options_and_more.py new file mode 100644 index 0000000..d08e853 --- /dev/null +++ b/blog/migrations/0005_alter_article_options_alter_category_options_and_more.py @@ -0,0 +1,300 @@ +# Generated by Django 4.2.5 on 2023-09-06 13:13 + +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): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('blog', '0004_rename_analyticscode_blogsettings_analytics_code_and_more'), + ] + + operations = [ + migrations.AlterModelOptions( + name='article', + options={'get_latest_by': 'id', 'ordering': ['-article_order', '-pub_time'], 'verbose_name': 'article', 'verbose_name_plural': 'article'}, + ), + migrations.AlterModelOptions( + name='category', + options={'ordering': ['-index'], 'verbose_name': 'category', 'verbose_name_plural': 'category'}, + ), + migrations.AlterModelOptions( + name='links', + options={'ordering': ['sequence'], 'verbose_name': 'link', 'verbose_name_plural': 'link'}, + ), + migrations.AlterModelOptions( + name='sidebar', + options={'ordering': ['sequence'], 'verbose_name': 'sidebar', 'verbose_name_plural': 'sidebar'}, + ), + migrations.AlterModelOptions( + name='tag', + options={'ordering': ['name'], 'verbose_name': 'tag', 'verbose_name_plural': 'tag'}, + ), + migrations.RemoveField( + model_name='article', + name='created_time', + ), + migrations.RemoveField( + model_name='article', + name='last_mod_time', + ), + migrations.RemoveField( + model_name='category', + name='created_time', + ), + migrations.RemoveField( + model_name='category', + name='last_mod_time', + ), + migrations.RemoveField( + model_name='links', + name='created_time', + ), + migrations.RemoveField( + model_name='sidebar', + name='created_time', + ), + migrations.RemoveField( + model_name='tag', + name='created_time', + ), + migrations.RemoveField( + model_name='tag', + name='last_mod_time', + ), + migrations.AddField( + model_name='article', + name='creation_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='creation time'), + ), + migrations.AddField( + model_name='article', + name='last_modify_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='modify time'), + ), + migrations.AddField( + model_name='category', + name='creation_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='creation time'), + ), + migrations.AddField( + model_name='category', + name='last_modify_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='modify time'), + ), + migrations.AddField( + model_name='links', + name='creation_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='creation time'), + ), + migrations.AddField( + model_name='sidebar', + name='creation_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='creation time'), + ), + migrations.AddField( + model_name='tag', + name='creation_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='creation time'), + ), + migrations.AddField( + model_name='tag', + name='last_modify_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='modify time'), + ), + migrations.AlterField( + model_name='article', + name='article_order', + field=models.IntegerField(default=0, verbose_name='order'), + ), + migrations.AlterField( + model_name='article', + name='author', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='author'), + ), + migrations.AlterField( + model_name='article', + name='body', + field=mdeditor.fields.MDTextField(verbose_name='body'), + ), + migrations.AlterField( + model_name='article', + name='category', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='blog.category', verbose_name='category'), + ), + migrations.AlterField( + model_name='article', + name='comment_status', + field=models.CharField(choices=[('o', 'Open'), ('c', 'Close')], default='o', max_length=1, verbose_name='comment status'), + ), + migrations.AlterField( + model_name='article', + name='pub_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='publish time'), + ), + migrations.AlterField( + model_name='article', + name='show_toc', + field=models.BooleanField(default=False, verbose_name='show toc'), + ), + migrations.AlterField( + model_name='article', + name='status', + field=models.CharField(choices=[('d', 'Draft'), ('p', 'Published')], default='p', max_length=1, verbose_name='status'), + ), + migrations.AlterField( + model_name='article', + name='tags', + field=models.ManyToManyField(blank=True, to='blog.tag', verbose_name='tag'), + ), + migrations.AlterField( + model_name='article', + name='title', + field=models.CharField(max_length=200, unique=True, verbose_name='title'), + ), + migrations.AlterField( + model_name='article', + name='type', + field=models.CharField(choices=[('a', 'Article'), ('p', 'Page')], default='a', max_length=1, verbose_name='type'), + ), + migrations.AlterField( + model_name='article', + name='views', + field=models.PositiveIntegerField(default=0, verbose_name='views'), + ), + migrations.AlterField( + model_name='blogsettings', + name='article_comment_count', + field=models.IntegerField(default=5, verbose_name='article comment count'), + ), + migrations.AlterField( + model_name='blogsettings', + name='article_sub_length', + field=models.IntegerField(default=300, verbose_name='article sub length'), + ), + migrations.AlterField( + model_name='blogsettings', + name='google_adsense_codes', + field=models.TextField(blank=True, default='', max_length=2000, null=True, verbose_name='adsense code'), + ), + migrations.AlterField( + model_name='blogsettings', + name='open_site_comment', + field=models.BooleanField(default=True, verbose_name='open site comment'), + ), + migrations.AlterField( + model_name='blogsettings', + name='show_google_adsense', + field=models.BooleanField(default=False, verbose_name='show adsense'), + ), + migrations.AlterField( + model_name='blogsettings', + name='sidebar_article_count', + field=models.IntegerField(default=10, verbose_name='sidebar article count'), + ), + migrations.AlterField( + model_name='blogsettings', + name='sidebar_comment_count', + field=models.IntegerField(default=5, verbose_name='sidebar comment count'), + ), + migrations.AlterField( + model_name='blogsettings', + name='site_description', + field=models.TextField(default='', max_length=1000, verbose_name='site description'), + ), + migrations.AlterField( + model_name='blogsettings', + name='site_keywords', + field=models.TextField(default='', max_length=1000, verbose_name='site keywords'), + ), + migrations.AlterField( + model_name='blogsettings', + name='site_name', + field=models.CharField(default='', max_length=200, verbose_name='site name'), + ), + migrations.AlterField( + model_name='blogsettings', + name='site_seo_description', + field=models.TextField(default='', max_length=1000, verbose_name='site seo description'), + ), + migrations.AlterField( + model_name='category', + name='index', + field=models.IntegerField(default=0, verbose_name='index'), + ), + migrations.AlterField( + model_name='category', + name='name', + field=models.CharField(max_length=30, unique=True, verbose_name='category name'), + ), + migrations.AlterField( + model_name='category', + name='parent_category', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='blog.category', verbose_name='parent category'), + ), + migrations.AlterField( + model_name='links', + name='is_enable', + field=models.BooleanField(default=True, verbose_name='is show'), + ), + migrations.AlterField( + model_name='links', + name='last_mod_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='modify time'), + ), + migrations.AlterField( + model_name='links', + name='link', + field=models.URLField(verbose_name='link'), + ), + migrations.AlterField( + model_name='links', + name='name', + field=models.CharField(max_length=30, unique=True, verbose_name='link name'), + ), + migrations.AlterField( + model_name='links', + name='sequence', + field=models.IntegerField(unique=True, verbose_name='order'), + ), + migrations.AlterField( + model_name='links', + name='show_type', + field=models.CharField(choices=[('i', 'index'), ('l', 'list'), ('p', 'post'), ('a', 'all'), ('s', 'slide')], default='i', max_length=1, verbose_name='show type'), + ), + migrations.AlterField( + model_name='sidebar', + name='content', + field=models.TextField(verbose_name='content'), + ), + migrations.AlterField( + model_name='sidebar', + name='is_enable', + field=models.BooleanField(default=True, verbose_name='is enable'), + ), + migrations.AlterField( + model_name='sidebar', + name='last_mod_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='modify time'), + ), + migrations.AlterField( + model_name='sidebar', + name='name', + field=models.CharField(max_length=100, verbose_name='title'), + ), + migrations.AlterField( + model_name='sidebar', + name='sequence', + field=models.IntegerField(unique=True, verbose_name='order'), + ), + migrations.AlterField( + model_name='tag', + name='name', + field=models.CharField(max_length=30, unique=True, verbose_name='tag name'), + ), + ] diff --git a/blog/migrations/0006_alter_blogsettings_options.py b/blog/migrations/0006_alter_blogsettings_options.py new file mode 100644 index 0000000..e36feb4 --- /dev/null +++ b/blog/migrations/0006_alter_blogsettings_options.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2.7 on 2024-01-26 02:41 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('blog', '0005_alter_article_options_alter_category_options_and_more'), + ] + + operations = [ + migrations.AlterModelOptions( + name='blogsettings', + options={'verbose_name': 'Website configuration', 'verbose_name_plural': 'Website configuration'}, + ), + ] diff --git a/blog/migrations/__init__.py b/blog/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/blog/models.py b/blog/models.py new file mode 100644 index 0000000..083788b --- /dev/null +++ b/blog/models.py @@ -0,0 +1,376 @@ +import logging +import re +from abc import abstractmethod + +from django.conf import settings +from django.core.exceptions import ValidationError +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 mdeditor.fields import MDTextField +from uuslug import slugify + +from djangoblog.utils import cache_decorator, cache +from djangoblog.utils import get_current_site + +logger = logging.getLogger(__name__) + + +class LinkShowType(models.TextChoices): + I = ('i', _('index')) + L = ('l', _('list')) + P = ('p', _('post')) + A = ('a', _('all')) + S = ('s', _('slide')) + + +class BaseModel(models.Model): + id = models.AutoField(primary_key=True) + creation_time = models.DateTimeField(_('creation time'), default=now) + last_modify_time = models.DateTimeField(_('modify time'), default=now) + + def save(self, *args, **kwargs): + is_update_views = isinstance( + self, + Article) and 'update_fields' in kwargs and kwargs['update_fields'] == ['views'] + if is_update_views: + Article.objects.filter(pk=self.pk).update(views=self.views) + else: + if 'slug' in self.__dict__: + slug = getattr( + self, 'title') if 'title' in self.__dict__ else getattr( + self, 'name') + setattr(self, 'slug', slugify(slug)) + super().save(*args, **kwargs) + + def get_full_url(self): + site = get_current_site().domain + url = "https://{site}{path}".format(site=site, + path=self.get_absolute_url()) + return url + + class Meta: + abstract = True + + @abstractmethod + def get_absolute_url(self): + pass + + +class Article(BaseModel): + """文章""" + STATUS_CHOICES = ( + ('d', _('Draft')), + ('p', _('Published')), + ) + COMMENT_STATUS = ( + ('o', _('Open')), + ('c', _('Close')), + ) + TYPE = ( + ('a', _('Article')), + ('p', _('Page')), + ) + title = models.CharField(_('title'), max_length=200, unique=True) + body = MDTextField(_('body')) + pub_time = models.DateTimeField( + _('publish time'), blank=False, null=False, default=now) + status = models.CharField( + _('status'), + max_length=1, + choices=STATUS_CHOICES, + default='p') + comment_status = models.CharField( + _('comment status'), + max_length=1, + choices=COMMENT_STATUS, + default='o') + type = models.CharField(_('type'), max_length=1, choices=TYPE, default='a') + views = models.PositiveIntegerField(_('views'), default=0) + author = models.ForeignKey( + settings.AUTH_USER_MODEL, + verbose_name=_('author'), + blank=False, + null=False, + on_delete=models.CASCADE) + article_order = models.IntegerField( + _('order'), blank=False, null=False, default=0) + show_toc = models.BooleanField(_('show toc'), blank=False, null=False, default=False) + category = models.ForeignKey( + 'Category', + verbose_name=_('category'), + on_delete=models.CASCADE, + blank=False, + null=False) + tags = models.ManyToManyField('Tag', verbose_name=_('tag'), blank=True) + + def body_to_string(self): + return self.body + + def __str__(self): + return self.title + + class Meta: + ordering = ['-article_order', '-pub_time'] + verbose_name = _('article') + verbose_name_plural = verbose_name + get_latest_by = 'id' + + def get_absolute_url(self): + return reverse('blog:detailbyid', kwargs={ + 'article_id': self.id, + 'year': self.creation_time.year, + 'month': self.creation_time.month, + 'day': self.creation_time.day + }) + + @cache_decorator(60 * 60 * 10) + def get_category_tree(self): + tree = self.category.get_category_tree() + names = list(map(lambda c: (c.name, c.get_absolute_url()), tree)) + + return names + + def save(self, *args, **kwargs): + super().save(*args, **kwargs) + + def viewed(self): + self.views += 1 + self.save(update_fields=['views']) + + def comment_list(self): + cache_key = 'article_comments_{id}'.format(id=self.id) + value = cache.get(cache_key) + if value: + logger.info('get article comments:{id}'.format(id=self.id)) + return value + else: + comments = self.comment_set.filter(is_enable=True).order_by('-id') + cache.set(cache_key, comments, 60 * 100) + logger.info('set article comments:{id}'.format(id=self.id)) + return comments + + def get_admin_url(self): + info = (self._meta.app_label, self._meta.model_name) + return reverse('admin:%s_%s_change' % info, args=(self.pk,)) + + @cache_decorator(expiration=60 * 100) + def next_article(self): + # 下一篇 + return Article.objects.filter( + id__gt=self.id, status='p').order_by('id').first() + + @cache_decorator(expiration=60 * 100) + def prev_article(self): + # 前一篇 + return Article.objects.filter(id__lt=self.id, status='p').first() + + def get_first_image_url(self): + """ + Get the first image url from article.body. + :return: + """ + match = re.search(r'!\[.*?\]\((.+?)\)', self.body) + if match: + return match.group(1) + return "" + + +class Category(BaseModel): + """文章分类""" + name = models.CharField(_('category name'), max_length=30, unique=True) + parent_category = models.ForeignKey( + 'self', + verbose_name=_('parent category'), + blank=True, + null=True, + on_delete=models.CASCADE) + slug = models.SlugField(default='no-slug', max_length=60, blank=True) + index = models.IntegerField(default=0, verbose_name=_('index')) + + class Meta: + ordering = ['-index'] + verbose_name = _('category') + verbose_name_plural = verbose_name + + def get_absolute_url(self): + return reverse( + 'blog:category_detail', kwargs={ + 'category_name': self.slug}) + + def __str__(self): + return self.name + + @cache_decorator(60 * 60 * 10) + def get_category_tree(self): + """ + 递归获得分类目录的父级 + :return: + """ + categorys = [] + + def parse(category): + categorys.append(category) + if category.parent_category: + parse(category.parent_category) + + parse(self) + return categorys + + @cache_decorator(60 * 60 * 10) + def get_sub_categorys(self): + """ + 获得当前分类目录所有子集 + :return: + """ + categorys = [] + all_categorys = Category.objects.all() + + def parse(category): + if category not in categorys: + categorys.append(category) + childs = all_categorys.filter(parent_category=category) + for child in childs: + if category not in categorys: + categorys.append(child) + parse(child) + + parse(self) + return categorys + + +class Tag(BaseModel): + """文章标签""" + name = models.CharField(_('tag name'), max_length=30, unique=True) + slug = models.SlugField(default='no-slug', max_length=60, blank=True) + + def __str__(self): + return self.name + + def get_absolute_url(self): + return reverse('blog:tag_detail', kwargs={'tag_name': self.slug}) + + @cache_decorator(60 * 60 * 10) + def get_article_count(self): + return Article.objects.filter(tags__name=self.name).distinct().count() + + class Meta: + ordering = ['name'] + verbose_name = _('tag') + verbose_name_plural = verbose_name + + +class Links(models.Model): + """友情链接""" + + name = models.CharField(_('link name'), max_length=30, unique=True) + link = models.URLField(_('link')) + sequence = models.IntegerField(_('order'), unique=True) + is_enable = models.BooleanField( + _('is show'), default=True, blank=False, null=False) + show_type = models.CharField( + _('show type'), + max_length=1, + choices=LinkShowType.choices, + default=LinkShowType.I) + creation_time = models.DateTimeField(_('creation time'), default=now) + last_mod_time = models.DateTimeField(_('modify time'), default=now) + + class Meta: + ordering = ['sequence'] + verbose_name = _('link') + verbose_name_plural = verbose_name + + def __str__(self): + return self.name + + +class SideBar(models.Model): + """侧边栏,可以展示一些html内容""" + name = models.CharField(_('title'), max_length=100) + content = models.TextField(_('content')) + sequence = models.IntegerField(_('order'), unique=True) + is_enable = models.BooleanField(_('is enable'), default=True) + creation_time = models.DateTimeField(_('creation time'), default=now) + last_mod_time = models.DateTimeField(_('modify time'), default=now) + + class Meta: + ordering = ['sequence'] + verbose_name = _('sidebar') + verbose_name_plural = verbose_name + + def __str__(self): + return self.name + + +class BlogSettings(models.Model): + """blog的配置""" + site_name = models.CharField( + _('site name'), + max_length=200, + null=False, + blank=False, + default='') + site_description = models.TextField( + _('site description'), + max_length=1000, + null=False, + blank=False, + default='') + site_seo_description = models.TextField( + _('site seo description'), max_length=1000, null=False, blank=False, default='') + site_keywords = models.TextField( + _('site keywords'), + max_length=1000, + null=False, + blank=False, + default='') + article_sub_length = models.IntegerField(_('article sub length'), default=300) + sidebar_article_count = models.IntegerField(_('sidebar article count'), default=10) + sidebar_comment_count = models.IntegerField(_('sidebar comment count'), default=5) + article_comment_count = models.IntegerField(_('article comment count'), default=5) + show_google_adsense = models.BooleanField(_('show adsense'), default=False) + google_adsense_codes = models.TextField( + _('adsense code'), max_length=2000, null=True, blank=True, default='') + open_site_comment = models.BooleanField(_('open site comment'), default=True) + global_header = models.TextField("公共头部", null=True, blank=True, default='') + global_footer = models.TextField("公共尾部", null=True, blank=True, default='') + beian_code = models.CharField( + '备案号', + max_length=2000, + null=True, + blank=True, + default='') + analytics_code = models.TextField( + "网站统计代码", + max_length=1000, + null=False, + blank=False, + default='') + show_gongan_code = models.BooleanField( + '是否显示公安备案号', default=False, null=False) + gongan_beiancode = models.TextField( + '公安备案号', + max_length=2000, + null=True, + blank=True, + default='') + comment_need_review = models.BooleanField( + '评论是否需要审核', default=False, null=False) + + class Meta: + verbose_name = _('Website configuration') + verbose_name_plural = verbose_name + + def __str__(self): + return self.site_name + + def clean(self): + if BlogSettings.objects.exclude(id=self.id).count(): + raise ValidationError(_('There can only be one configuration')) + + def save(self, *args, **kwargs): + super().save(*args, **kwargs) + from djangoblog.utils import cache + cache.clear() diff --git a/blog/search_indexes.py b/blog/search_indexes.py new file mode 100644 index 0000000..7f1dfac --- /dev/null +++ b/blog/search_indexes.py @@ -0,0 +1,13 @@ +from haystack import indexes + +from blog.models import Article + + +class ArticleIndex(indexes.SearchIndex, indexes.Indexable): + text = indexes.CharField(document=True, use_template=True) + + def get_model(self): + return Article + + def index_queryset(self, using=None): + return self.get_model().objects.filter(status='p') diff --git a/blog/templatetags/__init__.py b/blog/templatetags/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/blog/templatetags/blog_tags.py b/blog/templatetags/blog_tags.py new file mode 100644 index 0000000..d6cd5d5 --- /dev/null +++ b/blog/templatetags/blog_tags.py @@ -0,0 +1,344 @@ +import hashlib +import logging +import random +import urllib + +from django import template +from django.conf import settings +from django.db.models import Q +from django.shortcuts import get_object_or_404 +from django.template.defaultfilters import stringfilter +from django.templatetags.static import static +from django.urls import reverse +from django.utils.safestring import mark_safe + +from blog.models import Article, Category, Tag, Links, SideBar, LinkShowType +from comments.models import Comment +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__) + +register = template.Library() + + +@register.simple_tag(takes_context=True) +def head_meta(context): + return mark_safe(hooks.apply_filters('head_meta', '', context)) + + +@register.simple_tag +def timeformat(data): + try: + return data.strftime(settings.TIME_FORMAT) + except Exception as e: + logger.error(e) + return "" + + +@register.simple_tag +def datetimeformat(data): + try: + return data.strftime(settings.DATE_TIME_FORMAT) + except Exception as e: + logger.error(e) + return "" + + +@register.filter() +@stringfilter +def custom_markdown(content): + return mark_safe(CommonMarkdown.get_markdown(content)) + + +@register.simple_tag +def get_markdown_toc(content): + from djangoblog.utils import CommonMarkdown + body, toc = CommonMarkdown.get_markdown_with_toc(content) + return mark_safe(toc) + + +@register.filter() +@stringfilter +def comment_markdown(content): + content = CommonMarkdown.get_markdown(content) + return mark_safe(sanitize_html(content)) + + +@register.filter(is_safe=True) +@stringfilter +def truncatechars_content(content): + """ + 获得文章内容的摘要 + :param content: + :return: + """ + from django.template.defaultfilters import truncatechars_html + from djangoblog.utils import get_blog_setting + blogsetting = get_blog_setting() + return truncatechars_html(content, blogsetting.article_sub_length) + + +@register.filter(is_safe=True) +@stringfilter +def truncate(content): + from django.utils.html import strip_tags + + return strip_tags(content)[:150] + + +@register.inclusion_tag('blog/tags/breadcrumb.html') +def load_breadcrumb(article): + """ + 获得文章面包屑 + :param article: + :return: + """ + names = article.get_category_tree() + from djangoblog.utils import get_blog_setting + blogsetting = get_blog_setting() + site = get_current_site().domain + names.append((blogsetting.site_name, '/')) + names = names[::-1] + + return { + 'names': names, + 'title': article.title, + 'count': len(names) + 1 + } + + +@register.inclusion_tag('blog/tags/article_tag_list.html') +def load_articletags(article): + """ + 文章标签 + :param article: + :return: + """ + tags = article.tags.all() + tags_list = [] + for tag in tags: + url = tag.get_absolute_url() + count = tag.get_article_count() + tags_list.append(( + url, count, tag, random.choice(settings.BOOTSTRAP_COLOR_TYPES) + )) + return { + 'article_tags_list': tags_list + } + + +@register.inclusion_tag('blog/tags/sidebar.html') +def load_sidebar(user, linktype): + """ + 加载侧边栏 + :return: + """ + value = cache.get("sidebar" + linktype) + if value: + value['user'] = user + return value + else: + logger.info('load sidebar') + from djangoblog.utils import get_blog_setting + blogsetting = get_blog_setting() + recent_articles = Article.objects.filter( + status='p')[:blogsetting.sidebar_article_count] + sidebar_categorys = Category.objects.all() + extra_sidebars = SideBar.objects.filter( + is_enable=True).order_by('sequence') + most_read_articles = Article.objects.filter(status='p').order_by( + '-views')[:blogsetting.sidebar_article_count] + dates = Article.objects.datetimes('creation_time', 'month', order='DESC') + links = Links.objects.filter(is_enable=True).filter( + Q(show_type=str(linktype)) | Q(show_type=LinkShowType.A)) + commment_list = Comment.objects.filter(is_enable=True).order_by( + '-id')[:blogsetting.sidebar_comment_count] + # 标签云 计算字体大小 + # 根据总数计算出平均值 大小为 (数目/平均值)*步长 + increment = 5 + tags = Tag.objects.all() + sidebar_tags = None + if tags and len(tags) > 0: + s = [t for t in [(t, t.get_article_count()) for t in tags] if t[1]] + count = sum([t[1] for t in s]) + dd = 1 if (count == 0 or not len(tags)) else count / len(tags) + import random + sidebar_tags = list( + map(lambda x: (x[0], x[1], (x[1] / dd) * increment + 10), s)) + random.shuffle(sidebar_tags) + + value = { + 'recent_articles': recent_articles, + 'sidebar_categorys': sidebar_categorys, + 'most_read_articles': most_read_articles, + 'article_dates': dates, + 'sidebar_comments': commment_list, + 'sidabar_links': links, + 'show_google_adsense': blogsetting.show_google_adsense, + 'google_adsense_codes': blogsetting.google_adsense_codes, + 'open_site_comment': blogsetting.open_site_comment, + 'show_gongan_code': blogsetting.show_gongan_code, + 'sidebar_tags': sidebar_tags, + 'extra_sidebars': extra_sidebars + } + cache.set("sidebar" + linktype, value, 60 * 60 * 60 * 3) + logger.info('set sidebar cache.key:{key}'.format(key="sidebar" + linktype)) + value['user'] = user + return value + + +@register.inclusion_tag('blog/tags/article_meta_info.html') +def load_article_metas(article, user): + """ + 获得文章meta信息 + :param article: + :return: + """ + return { + 'article': article, + 'user': user + } + + +@register.inclusion_tag('blog/tags/article_pagination.html') +def load_pagination_info(page_obj, page_type, tag_name): + previous_url = '' + next_url = '' + if page_type == '': + if page_obj.has_next(): + next_number = page_obj.next_page_number() + next_url = reverse('blog:index_page', kwargs={'page': next_number}) + if page_obj.has_previous(): + previous_number = page_obj.previous_page_number() + previous_url = reverse( + 'blog:index_page', kwargs={ + 'page': previous_number}) + if page_type == '分类标签归档': + tag = get_object_or_404(Tag, name=tag_name) + if page_obj.has_next(): + next_number = page_obj.next_page_number() + next_url = reverse( + 'blog:tag_detail_page', + kwargs={ + 'page': next_number, + 'tag_name': tag.slug}) + if page_obj.has_previous(): + previous_number = page_obj.previous_page_number() + previous_url = reverse( + 'blog:tag_detail_page', + kwargs={ + 'page': previous_number, + 'tag_name': tag.slug}) + if page_type == '作者文章归档': + if page_obj.has_next(): + next_number = page_obj.next_page_number() + next_url = reverse( + 'blog:author_detail_page', + kwargs={ + 'page': next_number, + 'author_name': tag_name}) + if page_obj.has_previous(): + previous_number = page_obj.previous_page_number() + previous_url = reverse( + 'blog:author_detail_page', + kwargs={ + 'page': previous_number, + 'author_name': tag_name}) + + if page_type == '分类目录归档': + category = get_object_or_404(Category, name=tag_name) + if page_obj.has_next(): + next_number = page_obj.next_page_number() + next_url = reverse( + 'blog:category_detail_page', + kwargs={ + 'page': next_number, + 'category_name': category.slug}) + if page_obj.has_previous(): + previous_number = page_obj.previous_page_number() + previous_url = reverse( + 'blog:category_detail_page', + kwargs={ + 'page': previous_number, + 'category_name': category.slug}) + + return { + 'previous_url': previous_url, + 'next_url': next_url, + 'page_obj': page_obj + } + + +@register.inclusion_tag('blog/tags/article_info.html') +def load_article_detail(article, isindex, user): + """ + 加载文章详情 + :param article: + :param isindex:是否列表页,若是列表页只显示摘要 + :return: + """ + from djangoblog.utils import get_blog_setting + blogsetting = get_blog_setting() + + return { + 'article': article, + 'isindex': isindex, + 'user': user, + 'open_site_comment': blogsetting.open_site_comment, + } + + +# return only the URL of the gravatar +# TEMPLATE USE: {{ email|gravatar_url:150 }} +@register.filter +def gravatar_url(email, size=40): + """获得gravatar头像""" + cachekey = 'gravatat/' + email + url = cache.get(cachekey) + if url: + return url + else: + usermodels = OAuthUser.objects.filter(email=email) + if usermodels: + o = list(filter(lambda x: x.picture is not None, usermodels)) + if o: + return o[0].picture + email = email.encode('utf-8') + + default = static('blog/img/avatar.png') + + url = "https://www.gravatar.com/avatar/%s?%s" % (hashlib.md5( + email.lower()).hexdigest(), urllib.parse.urlencode({'d': default, 's': str(size)})) + cache.set(cachekey, url, 60 * 60 * 10) + logger.info('set gravatar cache.key:{key}'.format(key=cachekey)) + return url + + +@register.filter +def gravatar(email, size=40): + """获得gravatar头像""" + url = gravatar_url(email, size) + return mark_safe( + '' % + (url, size, size)) + + +@register.simple_tag +def query(qs, **kwargs): + """ template tag which allows queryset filtering. Usage: + {% query books author=author as mybooks %} + {% for book in mybooks %} + ... + {% endfor %} + """ + return qs.filter(**kwargs) + + +@register.filter +def addstr(arg1, arg2): + """concatenate arg1 & arg2""" + return str(arg1) + str(arg2) diff --git a/blog/tests.py b/blog/tests.py new file mode 100644 index 0000000..ee13505 --- /dev/null +++ b/blog/tests.py @@ -0,0 +1,232 @@ +import os + +from django.conf import settings +from django.core.files.uploadedfile import SimpleUploadedFile +from django.core.management import call_command +from django.core.paginator import Paginator +from django.templatetags.static import static +from django.test import Client, RequestFactory, TestCase +from django.urls import reverse +from django.utils import timezone + +from accounts.models import BlogUser +from blog.forms import BlogSearchForm +from blog.models import Article, Category, Tag, SideBar, Links +from blog.templatetags.blog_tags import load_pagination_info, load_articletags +from djangoblog.utils import get_current_site, get_sha256 +from oauth.models import OAuthUser, OAuthConfig + + +# Create your tests here. + +class ArticleTest(TestCase): + def setUp(self): + self.client = Client() + self.factory = RequestFactory() + + def test_validate_article(self): + site = get_current_site().domain + user = BlogUser.objects.get_or_create( + email="liangliangyy@gmail.com", + username="liangliangyy")[0] + user.set_password("liangliangyy") + user.is_staff = True + user.is_superuser = True + user.save() + response = self.client.get(user.get_absolute_url()) + self.assertEqual(response.status_code, 200) + response = self.client.get('/admin/servermanager/emailsendlog/') + response = self.client.get('admin/admin/logentry/') + s = SideBar() + s.sequence = 1 + s.name = 'test' + s.content = 'test content' + s.is_enable = True + s.save() + + category = Category() + category.name = "category" + category.creation_time = timezone.now() + category.last_mod_time = timezone.now() + category.save() + + tag = Tag() + tag.name = "nicetag" + tag.save() + + article = Article() + article.title = "nicetitle" + article.body = "nicecontent" + article.author = user + article.category = category + article.type = 'a' + article.status = 'p' + + article.save() + self.assertEqual(0, article.tags.count()) + article.tags.add(tag) + article.save() + self.assertEqual(1, article.tags.count()) + + for i in range(20): + article = Article() + article.title = "nicetitle" + str(i) + article.body = "nicetitle" + str(i) + article.author = user + article.category = category + article.type = 'a' + article.status = 'p' + article.save() + article.tags.add(tag) + article.save() + from blog.documents import ELASTICSEARCH_ENABLED + if ELASTICSEARCH_ENABLED: + call_command("build_index") + response = self.client.get('/search', {'q': 'nicetitle'}) + self.assertEqual(response.status_code, 200) + + response = self.client.get(article.get_absolute_url()) + self.assertEqual(response.status_code, 200) + from djangoblog.spider_notify import SpiderNotify + SpiderNotify.notify(article.get_absolute_url()) + response = self.client.get(tag.get_absolute_url()) + self.assertEqual(response.status_code, 200) + + response = self.client.get(category.get_absolute_url()) + self.assertEqual(response.status_code, 200) + + response = self.client.get('/search', {'q': 'django'}) + self.assertEqual(response.status_code, 200) + s = load_articletags(article) + self.assertIsNotNone(s) + + self.client.login(username='liangliangyy', password='liangliangyy') + + response = self.client.get(reverse('blog:archives')) + self.assertEqual(response.status_code, 200) + + p = Paginator(Article.objects.all(), settings.PAGINATE_BY) + self.check_pagination(p, '', '') + + p = Paginator(Article.objects.filter(tags=tag), settings.PAGINATE_BY) + self.check_pagination(p, '分类标签归档', tag.slug) + + p = Paginator( + Article.objects.filter( + author__username='liangliangyy'), settings.PAGINATE_BY) + self.check_pagination(p, '作者文章归档', 'liangliangyy') + + p = Paginator(Article.objects.filter(category=category), settings.PAGINATE_BY) + self.check_pagination(p, '分类目录归档', category.slug) + + f = BlogSearchForm() + f.search() + # self.client.login(username='liangliangyy', password='liangliangyy') + from djangoblog.spider_notify import SpiderNotify + SpiderNotify.baidu_notify([article.get_full_url()]) + + from blog.templatetags.blog_tags import gravatar_url, gravatar + u = gravatar_url('liangliangyy@gmail.com') + u = gravatar('liangliangyy@gmail.com') + + link = Links( + sequence=1, + name="lylinux", + link='https://wwww.lylinux.net') + link.save() + response = self.client.get('/links.html') + self.assertEqual(response.status_code, 200) + + response = self.client.get('/feed/') + self.assertEqual(response.status_code, 200) + + response = self.client.get('/sitemap.xml') + self.assertEqual(response.status_code, 200) + + self.client.get("/admin/blog/article/1/delete/") + self.client.get('/admin/servermanager/emailsendlog/') + self.client.get('/admin/admin/logentry/') + self.client.get('/admin/admin/logentry/1/change/') + + def check_pagination(self, p, type, value): + for page in range(1, p.num_pages + 1): + s = load_pagination_info(p.page(page), type, value) + self.assertIsNotNone(s) + if s['previous_url']: + response = self.client.get(s['previous_url']) + self.assertEqual(response.status_code, 200) + if s['next_url']: + response = self.client.get(s['next_url']) + self.assertEqual(response.status_code, 200) + + def test_image(self): + import requests + rsp = requests.get( + 'https://www.python.org/static/img/python-logo.png') + imagepath = os.path.join(settings.BASE_DIR, 'python.png') + with open(imagepath, 'wb') as file: + file.write(rsp.content) + rsp = self.client.post('/upload') + self.assertEqual(rsp.status_code, 403) + sign = get_sha256(get_sha256(settings.SECRET_KEY)) + with open(imagepath, 'rb') as file: + imgfile = SimpleUploadedFile( + 'python.png', file.read(), content_type='image/jpg') + form_data = {'python.png': imgfile} + rsp = self.client.post( + '/upload?sign=' + sign, form_data, follow=True) + self.assertEqual(rsp.status_code, 200) + os.remove(imagepath) + from djangoblog.utils import save_user_avatar, send_email + send_email(['qq@qq.com'], 'testTitle', 'testContent') + save_user_avatar( + 'https://www.python.org/static/img/python-logo.png') + + def test_errorpage(self): + rsp = self.client.get('/eee') + self.assertEqual(rsp.status_code, 404) + + def test_commands(self): + user = BlogUser.objects.get_or_create( + email="liangliangyy@gmail.com", + username="liangliangyy")[0] + user.set_password("liangliangyy") + user.is_staff = True + user.is_superuser = True + user.save() + + c = OAuthConfig() + c.type = 'qq' + c.appkey = 'appkey' + c.appsecret = 'appsecret' + c.save() + + u = OAuthUser() + u.type = 'qq' + u.openid = 'openid' + u.user = user + u.picture = static("/blog/img/avatar.png") + u.metadata = ''' +{ +"figureurl": "https://qzapp.qlogo.cn/qzapp/101513904/C740E30B4113EAA80E0D9918ABC78E82/30" +}''' + u.save() + + u = OAuthUser() + u.type = 'qq' + u.openid = 'openid1' + u.picture = 'https://qzapp.qlogo.cn/qzapp/101513904/C740E30B4113EAA80E0D9918ABC78E82/30' + u.metadata = ''' + { + "figureurl": "https://qzapp.qlogo.cn/qzapp/101513904/C740E30B4113EAA80E0D9918ABC78E82/30" + }''' + u.save() + + from blog.documents import ELASTICSEARCH_ENABLED + if ELASTICSEARCH_ENABLED: + call_command("build_index") + call_command("ping_baidu", "all") + call_command("create_testdata") + call_command("clear_cache") + call_command("sync_user_avatar") + call_command("build_search_words") diff --git a/blog/urls.py b/blog/urls.py new file mode 100644 index 0000000..adf2703 --- /dev/null +++ b/blog/urls.py @@ -0,0 +1,62 @@ +from django.urls import path +from django.views.decorators.cache import cache_page + +from . import views + +app_name = "blog" +urlpatterns = [ + path( + r'', + views.IndexView.as_view(), + name='index'), + path( + r'page//', + views.IndexView.as_view(), + name='index_page'), + path( + r'article////.html', + views.ArticleDetailView.as_view(), + name='detailbyid'), + path( + r'category/.html', + views.CategoryDetailView.as_view(), + name='category_detail'), + path( + r'category//.html', + views.CategoryDetailView.as_view(), + name='category_detail_page'), + path( + r'author/.html', + views.AuthorDetailView.as_view(), + name='author_detail'), + path( + r'author//.html', + views.AuthorDetailView.as_view(), + name='author_detail_page'), + path( + r'tag/.html', + views.TagDetailView.as_view(), + name='tag_detail'), + path( + r'tag//.html', + views.TagDetailView.as_view(), + name='tag_detail_page'), + path( + 'archives.html', + cache_page( + 60 * 60)( + views.ArchivesView.as_view()), + name='archives'), + path( + 'links.html', + views.LinkListView.as_view(), + name='links'), + path( + r'upload', + views.fileupload, + name='upload'), + path( + r'clean', + views.clean_cache_view, + name='clean'), +] diff --git a/blog/views.py b/blog/views.py new file mode 100644 index 0000000..d5dc7ec --- /dev/null +++ b/blog/views.py @@ -0,0 +1,379 @@ +import logging +import os +import uuid + +from django.conf import settings +from django.core.paginator import Paginator +from django.http import HttpResponse, HttpResponseForbidden +from django.shortcuts import get_object_or_404 +from django.shortcuts import render +from django.templatetags.static import static +from django.utils import timezone +from django.utils.translation import gettext_lazy as _ +from django.views.decorators.csrf import csrf_exempt +from django.views.generic.detail import DetailView +from django.views.generic.list import ListView +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 + +logger = logging.getLogger(__name__) + + +class ArticleListView(ListView): + # template_name属性用于指定使用哪个模板进行渲染 + template_name = 'blog/article_index.html' + + # context_object_name属性用于给上下文变量取名(在模板中使用该名字) + context_object_name = 'article_list' + + # 页面类型,分类目录或标签列表等 + page_type = '' + paginate_by = settings.PAGINATE_BY + page_kwarg = 'page' + link_type = LinkShowType.L + + def get_view_cache_key(self): + return self.request.get['pages'] + + @property + def page_number(self): + page_kwarg = self.page_kwarg + page = self.kwargs.get( + page_kwarg) or self.request.GET.get(page_kwarg) or 1 + return page + + def get_queryset_cache_key(self): + """ + 子类重写.获得queryset的缓存key + """ + raise NotImplementedError() + + def get_queryset_data(self): + """ + 子类重写.获取queryset的数据 + """ + raise NotImplementedError() + + 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)) + return value + else: + article_list = self.get_queryset_data() + cache.set(cache_key, article_list) + logger.info('set view cache.key:{key}'.format(key=cache_key)) + return article_list + + def get_queryset(self): + ''' + 重写默认,从缓存获取数据 + :return: + ''' + key = self.get_queryset_cache_key() + value = self.get_queryset_from_cache(key) + return value + + def get_context_data(self, **kwargs): + kwargs['linktype'] = self.link_type + return super(ArticleListView, self).get_context_data(**kwargs) + + +class IndexView(ArticleListView): + ''' + 首页 + ''' + # 友情链接类型 + link_type = LinkShowType.I + + def get_queryset_data(self): + article_list = Article.objects.filter(type='a', status='p') + return article_list + + def get_queryset_cache_key(self): + cache_key = 'index_{page}'.format(page=self.page_number) + return cache_key + + +class ArticleDetailView(DetailView): + ''' + 文章详情页面 + ''' + template_name = 'blog/article_detail.html' + model = Article + pk_url_kwarg = 'article_id' + context_object_name = "article" + + def get_context_data(self, **kwargs): + comment_form = CommentForm() + + article_comments = self.object.comment_list() + parent_comments = article_comments.filter(parent_comment=None) + blog_setting = get_blog_setting() + paginator = Paginator(parent_comments, blog_setting.article_comment_count) + page = self.request.GET.get('comment_page', '1') + if not page.isnumeric(): + page = 1 + else: + page = int(page) + if page < 1: + page = 1 + if page > paginator.num_pages: + page = paginator.num_pages + + p_comments = paginator.page(page) + next_page = p_comments.next_page_number() if p_comments.has_next() else None + prev_page = p_comments.previous_page_number() if p_comments.has_previous() else None + + if next_page: + kwargs[ + 'comment_next_page_url'] = self.object.get_absolute_url() + f'?comment_page={next_page}#commentlist-container' + if prev_page: + kwargs[ + 'comment_prev_page_url'] = self.object.get_absolute_url() + f'?comment_page={prev_page}#commentlist-container' + kwargs['form'] = comment_form + kwargs['article_comments'] = article_comments + kwargs['p_comments'] = p_comments + kwargs['comment_count'] = len( + article_comments) if article_comments else 0 + + kwargs['next_article'] = self.object.next_article + kwargs['prev_article'] = self.object.prev_article + + context = super(ArticleDetailView, self).get_context_data(**kwargs) + article = self.object + # Action Hook, 通知插件"文章详情已获取" + hooks.run_action('after_article_body_get', article=article, request=self.request) + # # Filter Hook, 允许插件修改文章正文 + article.body = hooks.apply_filters(ARTICLE_CONTENT_HOOK_NAME, article.body, article=article, + request=self.request) + + return context + + +class CategoryDetailView(ArticleListView): + ''' + 分类目录列表 + ''' + page_type = "分类目录归档" + + def get_queryset_data(self): + slug = self.kwargs['category_name'] + category = get_object_or_404(Category, slug=slug) + + categoryname = category.name + self.categoryname = categoryname + categorynames = list( + map(lambda c: c.name, category.get_sub_categorys())) + article_list = Article.objects.filter( + category__name__in=categorynames, status='p') + return article_list + + def get_queryset_cache_key(self): + slug = self.kwargs['category_name'] + category = get_object_or_404(Category, slug=slug) + categoryname = category.name + self.categoryname = categoryname + cache_key = 'category_list_{categoryname}_{page}'.format( + categoryname=categoryname, page=self.page_number) + return cache_key + + def get_context_data(self, **kwargs): + + categoryname = self.categoryname + try: + categoryname = categoryname.split('/')[-1] + except BaseException: + pass + kwargs['page_type'] = CategoryDetailView.page_type + kwargs['tag_name'] = categoryname + return super(CategoryDetailView, self).get_context_data(**kwargs) + + +class AuthorDetailView(ArticleListView): + ''' + 作者详情页 + ''' + page_type = '作者文章归档' + + def get_queryset_cache_key(self): + from uuslug import slugify + author_name = slugify(self.kwargs['author_name']) + cache_key = 'author_{author_name}_{page}'.format( + author_name=author_name, page=self.page_number) + return cache_key + + def get_queryset_data(self): + author_name = self.kwargs['author_name'] + article_list = Article.objects.filter( + author__username=author_name, type='a', status='p') + return article_list + + def get_context_data(self, **kwargs): + author_name = self.kwargs['author_name'] + kwargs['page_type'] = AuthorDetailView.page_type + kwargs['tag_name'] = author_name + return super(AuthorDetailView, self).get_context_data(**kwargs) + + +class TagDetailView(ArticleListView): + ''' + 标签列表页面 + ''' + page_type = '分类标签归档' + + def get_queryset_data(self): + slug = self.kwargs['tag_name'] + tag = get_object_or_404(Tag, slug=slug) + tag_name = tag.name + self.name = tag_name + article_list = Article.objects.filter( + tags__name=tag_name, type='a', status='p') + return article_list + + def get_queryset_cache_key(self): + slug = self.kwargs['tag_name'] + tag = get_object_or_404(Tag, slug=slug) + tag_name = tag.name + self.name = tag_name + cache_key = 'tag_{tag_name}_{page}'.format( + tag_name=tag_name, page=self.page_number) + return cache_key + + def get_context_data(self, **kwargs): + # tag_name = self.kwargs['tag_name'] + tag_name = self.name + kwargs['page_type'] = TagDetailView.page_type + kwargs['tag_name'] = tag_name + return super(TagDetailView, self).get_context_data(**kwargs) + + +class ArchivesView(ArticleListView): + ''' + 文章归档页面 + ''' + page_type = '文章归档' + paginate_by = None + page_kwarg = None + template_name = 'blog/article_archives.html' + + def get_queryset_data(self): + return Article.objects.filter(status='p').all() + + def get_queryset_cache_key(self): + cache_key = 'archives' + return cache_key + + +class LinkListView(ListView): + model = Links + template_name = 'blog/links_list.html' + + def get_queryset(self): + return Links.objects.filter(is_enable=True) + + +class EsSearchView(SearchView): + def get_context(self): + paginator, page = self.build_page() + context = { + "query": self.query, + "form": self.form, + "page": page, + "paginator": paginator, + "suggestion": None, + } + if hasattr(self.results, "query") and self.results.query.backend.include_spelling: + context["suggestion"] = self.results.query.get_spelling_suggestion() + context.update(self.extra_context()) + + return context + + +@csrf_exempt +def fileupload(request): + """ + 该方法需自己写调用端来上传图片,该方法仅提供图床功能 + :param request: + :return: + """ + if request.method == 'POST': + sign = request.GET.get('sign', None) + if not sign: + return HttpResponseForbidden() + if not sign == get_sha256(get_sha256(settings.SECRET_KEY)): + return HttpResponseForbidden() + response = [] + for filename in request.FILES: + timestr = timezone.now().strftime('%Y/%m/%d') + imgextensions = ['jpg', 'png', 'jpeg', 'bmp'] + fname = u''.join(str(filename)) + isimage = len([i for i in imgextensions if fname.find(i) >= 0]) > 0 + base_dir = os.path.join(settings.STATICFILES, "files" if not isimage else "image", timestr) + if not os.path.exists(base_dir): + os.makedirs(base_dir) + savepath = os.path.normpath(os.path.join(base_dir, f"{uuid.uuid4().hex}{os.path.splitext(filename)[-1]}")) + if not savepath.startswith(base_dir): + return HttpResponse("only for post") + with open(savepath, 'wb+') as wfile: + for chunk in request.FILES[filename].chunks(): + wfile.write(chunk) + if isimage: + from PIL import Image + image = Image.open(savepath) + image.save(savepath, quality=20, optimize=True) + url = static(savepath) + response.append(url) + return HttpResponse(response) + + else: + return HttpResponse("only for post") + + +def page_not_found_view( + request, + exception, + template_name='blog/error_page.html'): + if exception: + logger.error(exception) + 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?'), + 'statuscode': '404'}, + status=404) + + +def server_error_view(request, template_name='blog/error_page.html'): + return render(request, + template_name, + {'message': _('Sorry, the server is busy, please click the home page to see other?'), + 'statuscode': '500'}, + status=500) + + +def permission_denied_view( + request, + exception, + template_name='blog/error_page.html'): + if exception: + logger.error(exception) + return render( + request, template_name, { + 'message': _('Sorry, you do not have permission to access this page?'), + 'statuscode': '403'}, status=403) + + +def clean_cache_view(request): + cache.clear() + return HttpResponse('ok') diff --git a/comments/__init__.py b/comments/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/comments/admin.py b/comments/admin.py new file mode 100644 index 0000000..a814f3f --- /dev/null +++ b/comments/admin.py @@ -0,0 +1,47 @@ +from django.contrib import admin +from django.urls import reverse +from django.utils.html import format_html +from django.utils.translation import gettext_lazy as _ + + +def disable_commentstatus(modeladmin, request, queryset): + queryset.update(is_enable=False) + + +def enable_commentstatus(modeladmin, request, queryset): + queryset.update(is_enable=True) + + +disable_commentstatus.short_description = _('Disable comments') +enable_commentstatus.short_description = _('Enable comments') + + +class CommentAdmin(admin.ModelAdmin): + list_per_page = 20 + list_display = ( + 'id', + 'body', + '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) + link = reverse('admin:%s_%s_change' % info, args=(obj.author.id,)) + 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') diff --git a/comments/apps.py b/comments/apps.py new file mode 100644 index 0000000..ff01b77 --- /dev/null +++ b/comments/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class CommentsConfig(AppConfig): + name = 'comments' diff --git a/comments/forms.py b/comments/forms.py new file mode 100644 index 0000000..e83737d --- /dev/null +++ b/comments/forms.py @@ -0,0 +1,13 @@ +from django import forms +from django.forms import ModelForm + +from .models import Comment + + +class CommentForm(ModelForm): + parent_comment_id = forms.IntegerField( + widget=forms.HiddenInput, required=False) + + class Meta: + model = Comment + fields = ['body'] diff --git a/comments/migrations/0001_initial.py b/comments/migrations/0001_initial.py new file mode 100644 index 0000000..61d1e53 --- /dev/null +++ b/comments/migrations/0001_initial.py @@ -0,0 +1,38 @@ +# Generated by Django 4.1.7 on 2023-03-02 07:14 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('blog', '0001_initial'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Comment', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('body', models.TextField(max_length=300, verbose_name='正文')), + ('created_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='创建时间')), + ('last_mod_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='修改时间')), + ('is_enable', models.BooleanField(default=True, verbose_name='是否显示')), + ('article', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='blog.article', verbose_name='文章')), + ('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='作者')), + ('parent_comment', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='comments.comment', verbose_name='上级评论')), + ], + options={ + 'verbose_name': '评论', + 'verbose_name_plural': '评论', + 'ordering': ['-id'], + 'get_latest_by': 'id', + }, + ), + ] diff --git a/comments/migrations/0002_alter_comment_is_enable.py b/comments/migrations/0002_alter_comment_is_enable.py new file mode 100644 index 0000000..17c44db --- /dev/null +++ b/comments/migrations/0002_alter_comment_is_enable.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.7 on 2023-04-24 13:48 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('comments', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='comment', + name='is_enable', + field=models.BooleanField(default=False, verbose_name='是否显示'), + ), + ] diff --git a/comments/migrations/0003_alter_comment_options_remove_comment_created_time_and_more.py b/comments/migrations/0003_alter_comment_options_remove_comment_created_time_and_more.py new file mode 100644 index 0000000..a1ca970 --- /dev/null +++ b/comments/migrations/0003_alter_comment_options_remove_comment_created_time_and_more.py @@ -0,0 +1,60 @@ +# Generated by Django 4.2.5 on 2023-09-06 13:13 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('blog', '0005_alter_article_options_alter_category_options_and_more'), + ('comments', '0002_alter_comment_is_enable'), + ] + + operations = [ + migrations.AlterModelOptions( + name='comment', + options={'get_latest_by': 'id', 'ordering': ['-id'], 'verbose_name': 'comment', 'verbose_name_plural': 'comment'}, + ), + migrations.RemoveField( + model_name='comment', + name='created_time', + ), + migrations.RemoveField( + model_name='comment', + name='last_mod_time', + ), + migrations.AddField( + model_name='comment', + name='creation_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='creation time'), + ), + migrations.AddField( + model_name='comment', + name='last_modify_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='last modify time'), + ), + migrations.AlterField( + model_name='comment', + name='article', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='blog.article', verbose_name='article'), + ), + migrations.AlterField( + model_name='comment', + name='author', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='author'), + ), + migrations.AlterField( + model_name='comment', + name='is_enable', + field=models.BooleanField(default=False, verbose_name='enable'), + ), + migrations.AlterField( + model_name='comment', + name='parent_comment', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='comments.comment', verbose_name='parent comment'), + ), + ] diff --git a/comments/migrations/__init__.py b/comments/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/comments/models.py b/comments/models.py new file mode 100644 index 0000000..7c3bbc8 --- /dev/null +++ b/comments/models.py @@ -0,0 +1,39 @@ +from django.conf import settings +from django.db import models +from django.utils.timezone import now +from django.utils.translation import gettext_lazy as _ + +from blog.models import Article + + +# Create your models here. + +class Comment(models.Model): + body = models.TextField('正文', max_length=300) + 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', + verbose_name=_('parent comment'), + blank=True, + null=True, + on_delete=models.CASCADE) + is_enable = models.BooleanField(_('enable'), + default=False, blank=False, null=False) + + class Meta: + ordering = ['-id'] + verbose_name = _('comment') + verbose_name_plural = verbose_name + get_latest_by = 'id' + + def __str__(self): + return self.body diff --git a/comments/templatetags/__init__.py b/comments/templatetags/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/comments/templatetags/comments_tags.py b/comments/templatetags/comments_tags.py new file mode 100644 index 0000000..fde02b4 --- /dev/null +++ b/comments/templatetags/comments_tags.py @@ -0,0 +1,30 @@ +from django import template + +register = template.Library() + + +@register.simple_tag +def parse_commenttree(commentlist, comment): + """获得当前评论子评论的列表 + 用法: {% parse_commenttree article_comments comment as childcomments %} + """ + datas = [] + + def parse(c): + childs = commentlist.filter(parent_comment=c, is_enable=True) + for child in childs: + datas.append(child) + parse(child) + + parse(comment) + return datas + + +@register.inclusion_tag('comments/tags/comment_item.html') +def show_comment_item(comment, ischild): + """评论""" + depth = 1 if ischild else 2 + return { + 'comment_item': comment, + 'depth': depth + } diff --git a/comments/tests.py b/comments/tests.py new file mode 100644 index 0000000..2a7f55f --- /dev/null +++ b/comments/tests.py @@ -0,0 +1,109 @@ +from django.test import Client, RequestFactory, TransactionTestCase +from django.urls import reverse + +from accounts.models import BlogUser +from blog.models import Category, Article +from comments.models import Comment +from comments.templatetags.comments_tags import * +from djangoblog.utils import get_max_articleid_commentid + + +# Create your tests here. + +class CommentsTest(TransactionTestCase): + def setUp(self): + self.client = Client() + self.factory = RequestFactory() + from blog.models import BlogSettings + value = BlogSettings() + value.comment_need_review = True + value.save() + + self.user = BlogUser.objects.create_superuser( + email="liangliangyy1@gmail.com", + username="liangliangyy1", + password="liangliangyy1") + + def update_article_comment_status(self, article): + comments = article.comment_set.all() + for comment in comments: + comment.is_enable = True + comment.save() + + def test_validate_comment(self): + self.client.login(username='liangliangyy1', password='liangliangyy1') + + category = Category() + category.name = "categoryccc" + category.save() + + article = Article() + article.title = "nicetitleccc" + article.body = "nicecontentccc" + article.author = self.user + article.category = category + article.type = 'a' + article.status = 'p' + article.save() + + comment_url = reverse( + 'comments:postcomment', kwargs={ + 'article_id': article.id}) + + response = self.client.post(comment_url, + { + 'body': '123ffffffffff' + }) + + self.assertEqual(response.status_code, 302) + + article = Article.objects.get(pk=article.pk) + self.assertEqual(len(article.comment_list()), 0) + self.update_article_comment_status(article) + + self.assertEqual(len(article.comment_list()), 1) + + response = self.client.post(comment_url, + { + 'body': '123ffffffffff', + }) + + self.assertEqual(response.status_code, 302) + + article = Article.objects.get(pk=article.pk) + self.update_article_comment_status(article) + self.assertEqual(len(article.comment_list()), 2) + parent_comment_id = article.comment_list()[0].id + + response = self.client.post(comment_url, + { + 'body': ''' + # Title1 + + ```python + import os + ``` + + [url](https://www.lylinux.net/) + + [ddd](http://www.baidu.com) + + + ''', + 'parent_comment_id': parent_comment_id + }) + + self.assertEqual(response.status_code, 302) + self.update_article_comment_status(article) + article = Article.objects.get(pk=article.pk) + self.assertEqual(len(article.comment_list()), 3) + comment = Comment.objects.get(id=parent_comment_id) + tree = parse_commenttree(article.comment_list(), comment) + self.assertEqual(len(tree), 1) + data = show_comment_item(comment, True) + self.assertIsNotNone(data) + s = get_max_articleid_commentid() + self.assertIsNotNone(s) + + from comments.utils import send_comment_email + send_comment_email(comment) diff --git a/comments/urls.py b/comments/urls.py new file mode 100644 index 0000000..7df3fab --- /dev/null +++ b/comments/urls.py @@ -0,0 +1,11 @@ +from django.urls import path + +from . import views + +app_name = "comments" +urlpatterns = [ + path( + 'article//postcomment', + views.CommentPostView.as_view(), + name='postcomment'), +] diff --git a/comments/utils.py b/comments/utils.py new file mode 100644 index 0000000..f01dba7 --- /dev/null +++ b/comments/utils.py @@ -0,0 +1,38 @@ +import logging + +from django.utils.translation import gettext_lazy as _ + +from djangoblog.utils import get_current_site +from djangoblog.utils import send_email + +logger = logging.getLogger(__name__) + + +def send_comment_email(comment): + site = get_current_site().domain + subject = _('Thanks for your comment') + article_url = f"https://{site}{comment.article.get_absolute_url()}" + html_content = _("""

Thank you very much for your comments on this site

+ You can visit %(article_title)s + to review your comments, + Thank you again! +
+ If the link above cannot be opened, please copy this link to your browser. + %(article_url)s""") % {'article_url': article_url, 'article_title': comment.article.title} + tomail = comment.author.email + send_email([tomail], subject, html_content) + try: + if comment.parent_comment: + html_content = _("""Your comment on %(article_title)s
has + received a reply.
%(comment_body)s +
+ go check it out! +
+ If the link above cannot be opened, please copy this link to your browser. + %(article_url)s + """) % {'article_url': article_url, 'article_title': comment.article.title, + 'comment_body': comment.parent_comment.body} + tomail = comment.parent_comment.author.email + send_email([tomail], subject, html_content) + except Exception as e: + logger.error(e) diff --git a/comments/views.py b/comments/views.py new file mode 100644 index 0000000..ad9b2b9 --- /dev/null +++ b/comments/views.py @@ -0,0 +1,63 @@ +# Create your views here. +from django.core.exceptions import ValidationError +from django.http import HttpResponseRedirect +from django.shortcuts import get_object_or_404 +from django.utils.decorators import method_decorator +from django.views.decorators.csrf import csrf_protect +from django.views.generic.edit import FormView + +from accounts.models import BlogUser +from blog.models import Article +from .forms import CommentForm +from .models import Comment + + +class CommentPostView(FormView): + form_class = CommentForm + template_name = 'blog/article_detail.html' + + @method_decorator(csrf_protect) + def dispatch(self, *args, **kwargs): + return super(CommentPostView, self).dispatch(*args, **kwargs) + + def get(self, request, *args, **kwargs): + article_id = self.kwargs['article_id'] + article = get_object_or_404(Article, pk=article_id) + url = article.get_absolute_url() + return HttpResponseRedirect(url + "#comments") + + def form_invalid(self, form): + article_id = self.kwargs['article_id'] + article = get_object_or_404(Article, pk=article_id) + + return self.render_to_response({ + 'form': form, + 'article': article + }) + + def form_valid(self, form): + """提交的数据验证合法后的逻辑""" + user = self.request.user + author = BlogUser.objects.get(pk=user.pk) + article_id = self.kwargs['article_id'] + article = get_object_or_404(Article, pk=article_id) + + if article.comment_status == 'c' or article.status == 'c': + raise ValidationError("该文章评论已关闭.") + comment = form.save(False) + comment.article = article + from djangoblog.utils import get_blog_setting + settings = get_blog_setting() + if not settings.comment_need_review: + comment.is_enable = True + comment.author = author + + if form.cleaned_data['parent_comment_id']: + parent_comment = Comment.objects.get( + pk=form.cleaned_data['parent_comment_id']) + comment.parent_comment = parent_comment + + comment.save(True) + return HttpResponseRedirect( + "%s#div-comment-%d" % + (article.get_absolute_url(), comment.pk)) diff --git a/deploy/docker-compose/docker-compose.es.yml b/deploy/docker-compose/docker-compose.es.yml new file mode 100644 index 0000000..83e35ff --- /dev/null +++ b/deploy/docker-compose/docker-compose.es.yml @@ -0,0 +1,48 @@ +version: '3' + +services: + es: + image: liangliangyy/elasticsearch-analysis-ik:8.6.1 + container_name: es + restart: always + environment: + - discovery.type=single-node + - "ES_JAVA_OPTS=-Xms512m -Xmx512m" + ports: + - 9200:9200 + volumes: + - ./bin/datas/es/:/usr/share/elasticsearch/data/ + + kibana: + image: kibana:8.6.1 + restart: always + container_name: kibana + ports: + - 5601:5601 + environment: + - ELASTICSEARCH_HOSTS=http://es:9200 + + djangoblog: + build: . + restart: always + command: bash -c 'sh /code/djangoblog/bin/docker_start.sh' + ports: + - "8000:8000" + volumes: + - ./collectedstatic:/code/djangoblog/collectedstatic + - ./uploads:/code/djangoblog/uploads + environment: + - DJANGO_MYSQL_DATABASE=djangoblog + - DJANGO_MYSQL_USER=root + - DJANGO_MYSQL_PASSWORD=DjAnGoBlOg!2!Q@W#E + - DJANGO_MYSQL_HOST=db + - DJANGO_MYSQL_PORT=3306 + - DJANGO_MEMCACHED_LOCATION=memcached:11211 + - DJANGO_ELASTICSEARCH_HOST=es:9200 + links: + - db + - memcached + depends_on: + - db + container_name: djangoblog + diff --git a/deploy/docker-compose/docker-compose.yml b/deploy/docker-compose/docker-compose.yml new file mode 100644 index 0000000..9609af3 --- /dev/null +++ b/deploy/docker-compose/docker-compose.yml @@ -0,0 +1,60 @@ +version: '3' + +services: + db: + image: mysql:latest + restart: always + environment: + - MYSQL_DATABASE=djangoblog + - MYSQL_ROOT_PASSWORD=DjAnGoBlOg!2!Q@W#E + ports: + - 3306:3306 + volumes: + - ./bin/datas/mysql/:/var/lib/mysql + depends_on: + - redis + container_name: db + + djangoblog: + build: + context: ../../ + restart: always + command: bash -c 'sh /code/djangoblog/bin/docker_start.sh' + ports: + - "8000:8000" + volumes: + - ./collectedstatic:/code/djangoblog/collectedstatic + - ./logs:/code/djangoblog/logs + - ./uploads:/code/djangoblog/uploads + environment: + - DJANGO_MYSQL_DATABASE=djangoblog + - DJANGO_MYSQL_USER=root + - DJANGO_MYSQL_PASSWORD=DjAnGoBlOg!2!Q@W#E + - DJANGO_MYSQL_HOST=db + - DJANGO_MYSQL_PORT=3306 + - DJANGO_REDIS_URL=redis:6379 + links: + - db + - redis + depends_on: + - db + container_name: djangoblog + nginx: + restart: always + image: nginx:latest + ports: + - "80:80" + - "443:443" + volumes: + - ./bin/nginx.conf:/etc/nginx/nginx.conf + - ./collectedstatic:/code/djangoblog/collectedstatic + links: + - djangoblog:djangoblog + container_name: nginx + + redis: + restart: always + image: redis:latest + container_name: redis + ports: + - "6379:6379" diff --git a/deploy/entrypoint.sh b/deploy/entrypoint.sh new file mode 100644 index 0000000..2fb6491 --- /dev/null +++ b/deploy/entrypoint.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash +NAME="djangoblog" +DJANGODIR=/code/djangoblog +USER=root +GROUP=root +NUM_WORKERS=1 +DJANGO_WSGI_MODULE=djangoblog.wsgi + + +echo "Starting $NAME as `whoami`" + +cd $DJANGODIR + +export PYTHONPATH=$DJANGODIR:$PYTHONPATH + +python manage.py makemigrations && \ + python manage.py migrate && \ + python manage.py collectstatic --noinput && \ + python manage.py compress --force && \ + python manage.py build_index && \ + python manage.py compilemessages || exit 1 + +exec gunicorn ${DJANGO_WSGI_MODULE}:application \ +--name $NAME \ +--workers $NUM_WORKERS \ +--user=$USER --group=$GROUP \ +--bind 0.0.0.0:8000 \ +--log-level=debug \ +--log-file=- \ +--worker-class gevent \ +--threads 4 diff --git a/deploy/k8s/configmap.yaml b/deploy/k8s/configmap.yaml new file mode 100644 index 0000000..835d4ad --- /dev/null +++ b/deploy/k8s/configmap.yaml @@ -0,0 +1,119 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: web-nginx-config + namespace: djangoblog +data: + nginx.conf: | + user nginx; + worker_processes auto; + error_log /var/log/nginx/error.log notice; + pid /var/run/nginx.pid; + + events { + worker_connections 1024; + multi_accept on; + use epoll; + } + + http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + keepalive_timeout 65; + gzip on; + gzip_disable "msie6"; + + gzip_vary on; + gzip_proxied any; + gzip_comp_level 8; + gzip_buffers 16 8k; + gzip_http_version 1.1; + gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png; + + # Include server configurations + include /etc/nginx/conf.d/*.conf; + } + djangoblog.conf: | + server { + server_name lylinux.net; + root /code/djangoblog/collectedstatic/; + listen 80; + keepalive_timeout 70; + location /static/ { + expires max; + alias /code/djangoblog/collectedstatic/; + } + + location ~* (robots\.txt|ads\.txt|favicon\.ico|favion\.ico|crossdomain\.xml|google93fd32dbd906620a\.html|BingSiteAuth\.xml|baidu_verify_Ijeny6KrmS\.html)$ { + root /resource/djangopub; + expires 1d; + access_log off; + error_log off; + } + + location / { + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Host $http_host; + proxy_set_header X-NginX-Proxy true; + proxy_redirect off; + if (!-f $request_filename) { + proxy_pass http://djangoblog:8000; + break; + } + } + } + server { + server_name www.lylinux.net; + listen 80; + return 301 https://lylinux.net$request_uri; + } + resource.lylinux.net.conf: | + server { + index index.html index.htm; + server_name resource.lylinux.net; + root /resource/; + + location /djangoblog/ { + alias /code/djangoblog/collectedstatic/; + } + + access_log off; + error_log off; + include lylinux/resource.conf; + } + lylinux.resource.conf: | + expires max; + access_log off; + log_not_found off; + add_header Pragma public; + add_header Cache-Control "public"; + add_header "Access-Control-Allow-Origin" "*"; + +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: djangoblog-env + namespace: djangoblog +data: + DJANGO_MYSQL_DATABASE: djangoblog + DJANGO_MYSQL_USER: db_user + DJANGO_MYSQL_PASSWORD: db_password + DJANGO_MYSQL_HOST: db_host + DJANGO_MYSQL_PORT: db_port + DJANGO_REDIS_URL: "redis:6379" + DJANGO_DEBUG: "False" + MYSQL_ROOT_PASSWORD: db_password + MYSQL_DATABASE: djangoblog + MYSQL_PASSWORD: db_password + DJANGO_SECRET_KEY: xxxxxxxxxxxxxxxxxxxxxxxxxxxxx + diff --git a/deploy/k8s/deployment.yaml b/deploy/k8s/deployment.yaml new file mode 100644 index 0000000..414fdcc --- /dev/null +++ b/deploy/k8s/deployment.yaml @@ -0,0 +1,274 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: djangoblog + namespace: djangoblog + labels: + app: djangoblog +spec: + replicas: 3 + selector: + matchLabels: + app: djangoblog + template: + metadata: + labels: + app: djangoblog + spec: + containers: + - name: djangoblog + image: liangliangyy/djangoblog:latest + imagePullPolicy: Always + ports: + - containerPort: 8000 + envFrom: + - configMapRef: + name: djangoblog-env + readinessProbe: + httpGet: + path: / + port: 8000 + initialDelaySeconds: 10 + periodSeconds: 30 + livenessProbe: + httpGet: + path: / + port: 8000 + initialDelaySeconds: 10 + periodSeconds: 30 + resources: + requests: + cpu: 10m + memory: 100Mi + limits: + cpu: "2" + memory: 2Gi + volumeMounts: + - name: djangoblog + mountPath: /code/djangoblog/collectedstatic + - name: resource + mountPath: /resource + volumes: + - name: djangoblog + persistentVolumeClaim: + claimName: djangoblog-pvc + - name: resource + persistentVolumeClaim: + claimName: resource-pvc + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: redis + namespace: djangoblog + labels: + app: redis +spec: + replicas: 1 + selector: + matchLabels: + app: redis + template: + metadata: + labels: + app: redis + spec: + containers: + - name: redis + image: redis:latest + imagePullPolicy: IfNotPresent + ports: + - containerPort: 6379 + resources: + requests: + cpu: 10m + memory: 100Mi + limits: + cpu: 200m + memory: 2Gi + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: db + namespace: djangoblog + labels: + app: db +spec: + replicas: 1 + selector: + matchLabels: + app: db + template: + metadata: + labels: + app: db + spec: + containers: + - name: db + image: mysql:latest + imagePullPolicy: IfNotPresent + ports: + - containerPort: 3306 + envFrom: + - configMapRef: + name: djangoblog-env + readinessProbe: + exec: + command: + - mysqladmin + - ping + - "-h" + - "127.0.0.1" + - "-u" + - "root" + - "-p$MYSQL_ROOT_PASSWORD" + initialDelaySeconds: 10 + periodSeconds: 10 + livenessProbe: + exec: + command: + - mysqladmin + - ping + - "-h" + - "127.0.0.1" + - "-u" + - "root" + - "-p$MYSQL_ROOT_PASSWORD" + initialDelaySeconds: 10 + periodSeconds: 10 + resources: + requests: + cpu: 10m + memory: 100Mi + limits: + cpu: "2" + memory: 2Gi + volumeMounts: + - name: db-data + mountPath: /var/lib/mysql + volumes: + - name: db-data + persistentVolumeClaim: + claimName: db-pvc + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx + namespace: djangoblog + labels: + app: nginx +spec: + replicas: 1 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:latest + imagePullPolicy: IfNotPresent + ports: + - containerPort: 80 + resources: + requests: + cpu: 10m + memory: 100Mi + limits: + cpu: "2" + memory: 2Gi + volumeMounts: + - name: nginx-config + mountPath: /etc/nginx/nginx.conf + subPath: nginx.conf + - name: nginx-config + mountPath: /etc/nginx/conf.d/default.conf + subPath: djangoblog.conf + - name: nginx-config + mountPath: /etc/nginx/conf.d/resource.lylinux.net.conf + subPath: resource.lylinux.net.conf + - name: nginx-config + mountPath: /etc/nginx/lylinux/resource.conf + subPath: lylinux.resource.conf + - name: djangoblog-pvc + mountPath: /code/djangoblog/collectedstatic + - name: resource-pvc + mountPath: /resource + volumes: + - name: nginx-config + configMap: + name: web-nginx-config + - name: djangoblog-pvc + persistentVolumeClaim: + claimName: djangoblog-pvc + - name: resource-pvc + persistentVolumeClaim: + claimName: resource-pvc + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: elasticsearch + namespace: djangoblog + labels: + app: elasticsearch +spec: + replicas: 1 + selector: + matchLabels: + app: elasticsearch + template: + metadata: + labels: + app: elasticsearch + spec: + containers: + - name: elasticsearch + image: liangliangyy/elasticsearch-analysis-ik:8.6.1 + imagePullPolicy: IfNotPresent + env: + - name: discovery.type + value: single-node + - name: ES_JAVA_OPTS + value: "-Xms256m -Xmx256m" + - name: xpack.security.enabled + value: "false" + - name: xpack.monitoring.templates.enabled + value: "false" + ports: + - containerPort: 9200 + resources: + requests: + cpu: 10m + memory: 100Mi + limits: + cpu: "2" + memory: 2Gi + readinessProbe: + httpGet: + path: / + port: 9200 + initialDelaySeconds: 15 + periodSeconds: 30 + livenessProbe: + httpGet: + path: / + port: 9200 + initialDelaySeconds: 15 + periodSeconds: 30 + volumeMounts: + - name: elasticsearch-data + mountPath: /usr/share/elasticsearch/data/ + volumes: + - name: elasticsearch-data + persistentVolumeClaim: + claimName: elasticsearch-pvc diff --git a/deploy/k8s/gateway.yaml b/deploy/k8s/gateway.yaml new file mode 100644 index 0000000..a8de073 --- /dev/null +++ b/deploy/k8s/gateway.yaml @@ -0,0 +1,17 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: nginx + namespace: djangoblog +spec: + ingressClassName: nginx + rules: + - http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: nginx + port: + number: 80 \ No newline at end of file diff --git a/deploy/k8s/pv.yaml b/deploy/k8s/pv.yaml new file mode 100644 index 0000000..874b72f --- /dev/null +++ b/deploy/k8s/pv.yaml @@ -0,0 +1,94 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: local-pv-db +spec: + capacity: + storage: 10Gi + volumeMode: Filesystem + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain + storageClassName: local-storage + local: + path: /mnt/local-storage-db + nodeAffinity: + required: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/hostname + operator: In + values: + - master +--- +apiVersion: v1 +kind: PersistentVolume +metadata: + name: local-pv-djangoblog +spec: + capacity: + storage: 5Gi + volumeMode: Filesystem + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain + storageClassName: local-storage + local: + path: /mnt/local-storage-djangoblog + nodeAffinity: + required: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/hostname + operator: In + values: + - master + + +--- +apiVersion: v1 +kind: PersistentVolume +metadata: + name: local-pv-resource +spec: + capacity: + storage: 5Gi + volumeMode: Filesystem + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain + storageClassName: local-storage + local: + path: /mnt/resource/ + nodeAffinity: + required: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/hostname + operator: In + values: + - master + +--- +apiVersion: v1 +kind: PersistentVolume +metadata: + name: local-pv-elasticsearch +spec: + capacity: + storage: 5Gi + volumeMode: Filesystem + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain + storageClassName: local-storage + local: + path: /mnt/local-storage-elasticsearch + nodeAffinity: + required: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/hostname + operator: In + values: + - master \ No newline at end of file diff --git a/deploy/k8s/pvc.yaml b/deploy/k8s/pvc.yaml new file mode 100644 index 0000000..ef238c5 --- /dev/null +++ b/deploy/k8s/pvc.yaml @@ -0,0 +1,60 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: db-pvc + namespace: djangoblog +spec: + storageClassName: local-storage + volumeName: local-pv-db + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi + + +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: djangoblog-pvc + namespace: djangoblog +spec: + volumeName: local-pv-djangoblog + storageClassName: local-storage + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 5Gi + +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: resource-pvc + namespace: djangoblog +spec: + volumeName: local-pv-resource + storageClassName: local-storage + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 5Gi + +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: elasticsearch-pvc + namespace: djangoblog +spec: + volumeName: local-pv-elasticsearch + storageClassName: local-storage + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 5Gi + \ No newline at end of file diff --git a/deploy/k8s/service.yaml b/deploy/k8s/service.yaml new file mode 100644 index 0000000..4ef2931 --- /dev/null +++ b/deploy/k8s/service.yaml @@ -0,0 +1,80 @@ +apiVersion: v1 +kind: Service +metadata: + name: djangoblog + namespace: djangoblog + labels: + app: djangoblog +spec: + selector: + app: djangoblog + ports: + - protocol: TCP + port: 8000 + targetPort: 8000 + type: ClusterIP +--- +apiVersion: v1 +kind: Service +metadata: + name: nginx + namespace: djangoblog + labels: + app: nginx +spec: + selector: + app: nginx + ports: + - protocol: TCP + port: 80 + targetPort: 80 + type: ClusterIP +--- +apiVersion: v1 +kind: Service +metadata: + name: redis + namespace: djangoblog + labels: + app: redis +spec: + selector: + app: redis + ports: + - protocol: TCP + port: 6379 + targetPort: 6379 + type: ClusterIP +--- +apiVersion: v1 +kind: Service +metadata: + name: db + namespace: djangoblog + labels: + app: db +spec: + selector: + app: db + ports: + - protocol: TCP + port: 3306 + targetPort: 3306 + type: ClusterIP +--- +apiVersion: v1 +kind: Service +metadata: + name: elasticsearch + namespace: djangoblog + labels: + app: elasticsearch +spec: + selector: + app: elasticsearch + ports: + - protocol: TCP + port: 9200 + targetPort: 9200 + type: ClusterIP + diff --git a/deploy/k8s/storageclass.yaml b/deploy/k8s/storageclass.yaml new file mode 100644 index 0000000..5d5a14c --- /dev/null +++ b/deploy/k8s/storageclass.yaml @@ -0,0 +1,10 @@ +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: local-storage + annotations: + storageclass.kubernetes.io/is-default-class: "true" +provisioner: kubernetes.io/no-provisioner +volumeBindingMode: Immediate + + diff --git a/deploy/nginx.conf b/deploy/nginx.conf new file mode 100644 index 0000000..32161d8 --- /dev/null +++ b/deploy/nginx.conf @@ -0,0 +1,50 @@ +user nginx; +worker_processes auto; + +error_log /var/log/nginx/error.log notice; +pid /var/run/nginx.pid; + + +events { + worker_connections 1024; +} + + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + #tcp_nopush on; + + keepalive_timeout 65; + + #gzip on; + + server { + root /code/djangoblog/collectedstatic/; + listen 80; + keepalive_timeout 70; + location /static/ { + expires max; + alias /code/djangoblog/collectedstatic/; + } + location / { + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Host $http_host; + proxy_set_header X-NginX-Proxy true; + proxy_redirect off; + if (!-f $request_filename) { + proxy_pass http://djangoblog:8000; + break; + } + } + } +} diff --git a/djangoblog/__init__.py b/djangoblog/__init__.py new file mode 100644 index 0000000..1e205f4 --- /dev/null +++ b/djangoblog/__init__.py @@ -0,0 +1 @@ +default_app_config = 'djangoblog.apps.DjangoblogAppConfig' diff --git a/djangoblog/admin_site.py b/djangoblog/admin_site.py new file mode 100644 index 0000000..f120405 --- /dev/null +++ b/djangoblog/admin_site.py @@ -0,0 +1,64 @@ +from django.contrib.admin import AdminSite +from django.contrib.admin.models import LogEntry +from django.contrib.sites.admin import SiteAdmin +from django.contrib.sites.models import Site + +from accounts.admin import * +from blog.admin import * +from blog.models import * +from comments.admin import * +from comments.models import * +from djangoblog.logentryadmin import LogEntryAdmin +from oauth.admin import * +from oauth.models import * +from owntracks.admin import * +from owntracks.models import * +from servermanager.admin import * +from servermanager.models import * + + +class DjangoBlogAdminSite(AdminSite): + site_header = 'djangoblog administration' + site_title = 'djangoblog site admin' + + def __init__(self, name='admin'): + super().__init__(name) + + def has_permission(self, request): + return request.user.is_superuser + + # def get_urls(self): + # urls = super().get_urls() + # from django.urls import path + # from blog.views import refresh_memcache + # + # my_urls = [ + # path('refresh/', self.admin_view(refresh_memcache), name="refresh"), + # ] + # return urls + my_urls + + +admin_site = DjangoBlogAdminSite(name='admin') + +admin_site.register(Article, ArticlelAdmin) +admin_site.register(Category, CategoryAdmin) +admin_site.register(Tag, TagAdmin) +admin_site.register(Links, LinksAdmin) +admin_site.register(SideBar, SideBarAdmin) +admin_site.register(BlogSettings, BlogSettingsAdmin) + +admin_site.register(commands, CommandsAdmin) +admin_site.register(EmailSendLog, EmailSendLogAdmin) + +admin_site.register(BlogUser, BlogUserAdmin) + +admin_site.register(Comment, CommentAdmin) + +admin_site.register(OAuthUser, OAuthUserAdmin) +admin_site.register(OAuthConfig, OAuthConfigAdmin) + +admin_site.register(OwnTrackLog, OwnTrackLogsAdmin) + +admin_site.register(Site, SiteAdmin) + +admin_site.register(LogEntry, LogEntryAdmin) diff --git a/djangoblog/apps.py b/djangoblog/apps.py new file mode 100644 index 0000000..d29e318 --- /dev/null +++ b/djangoblog/apps.py @@ -0,0 +1,11 @@ +from django.apps import AppConfig + +class DjangoblogAppConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'djangoblog' + + def ready(self): + super().ready() + # Import and load plugins here + from .plugin_manage.loader import load_plugins + load_plugins() \ No newline at end of file diff --git a/djangoblog/blog_signals.py b/djangoblog/blog_signals.py new file mode 100644 index 0000000..393f441 --- /dev/null +++ b/djangoblog/blog_signals.py @@ -0,0 +1,122 @@ +import _thread +import logging + +import django.dispatch +from django.conf import settings +from django.contrib.admin.models import LogEntry +from django.contrib.auth.signals import user_logged_in, user_logged_out +from django.core.mail import EmailMultiAlternatives +from django.db.models.signals import post_save +from django.dispatch import receiver + +from comments.models import Comment +from comments.utils import send_comment_email +from djangoblog.spider_notify import SpiderNotify +from djangoblog.utils import cache, expire_view_cache, delete_sidebar_cache, delete_view_cache +from djangoblog.utils import get_current_site +from oauth.models import OAuthUser + +logger = logging.getLogger(__name__) + +oauth_user_login_signal = django.dispatch.Signal(['id']) +send_email_signal = django.dispatch.Signal( + ['emailto', 'title', 'content']) + + +@receiver(send_email_signal) +def send_email_signal_handler(sender, **kwargs): + emailto = kwargs['emailto'] + title = kwargs['title'] + content = kwargs['content'] + + msg = EmailMultiAlternatives( + title, + content, + from_email=settings.DEFAULT_FROM_EMAIL, + to=emailto) + msg.content_subtype = "html" + + from servermanager.models import EmailSendLog + log = EmailSendLog() + log.title = title + log.content = content + log.emailto = ','.join(emailto) + + try: + result = msg.send() + log.send_result = result > 0 + except Exception as e: + logger.error(f"失败邮箱号: {emailto}, {e}") + log.send_result = False + log.save() + + +@receiver(oauth_user_login_signal) +def oauth_user_login_signal_handler(sender, **kwargs): + id = kwargs['id'] + oauthuser = OAuthUser.objects.get(id=id) + site = get_current_site().domain + if oauthuser.picture and not oauthuser.picture.find(site) >= 0: + from djangoblog.utils import save_user_avatar + oauthuser.picture = save_user_avatar(oauthuser.picture) + oauthuser.save() + + delete_sidebar_cache() + + +@receiver(post_save) +def model_post_save_callback( + sender, + instance, + created, + raw, + using, + update_fields, + **kwargs): + clearcache = False + if isinstance(instance, LogEntry): + return + if 'get_full_url' in dir(instance): + is_update_views = update_fields == {'views'} + if not settings.TESTING and not is_update_views: + try: + notify_url = instance.get_full_url() + SpiderNotify.baidu_notify([notify_url]) + except Exception as ex: + logger.error("notify sipder", ex) + if not is_update_views: + clearcache = True + + if isinstance(instance, Comment): + if instance.is_enable: + path = instance.article.get_absolute_url() + site = get_current_site().domain + if site.find(':') > 0: + site = site[0:site.find(':')] + + expire_view_cache( + path, + servername=site, + serverport=80, + key_prefix='blogdetail') + if cache.get('seo_processor'): + cache.delete('seo_processor') + comment_cache_key = 'article_comments_{id}'.format( + id=instance.article.id) + cache.delete(comment_cache_key) + delete_sidebar_cache() + delete_view_cache('article_comments', [str(instance.article.pk)]) + + _thread.start_new_thread(send_comment_email, (instance,)) + + if clearcache: + cache.clear() + + +@receiver(user_logged_in) +@receiver(user_logged_out) +def user_auth_callback(sender, request, user, **kwargs): + if user and user.username: + logger.info(user) + delete_sidebar_cache() + # cache.clear() diff --git a/djangoblog/elasticsearch_backend.py b/djangoblog/elasticsearch_backend.py new file mode 100644 index 0000000..4afe498 --- /dev/null +++ b/djangoblog/elasticsearch_backend.py @@ -0,0 +1,183 @@ +from django.utils.encoding import force_str +from elasticsearch_dsl import Q +from haystack.backends import BaseEngine, BaseSearchBackend, BaseSearchQuery, log_query +from haystack.forms import ModelSearchForm +from haystack.models import SearchResult +from haystack.utils import log as logging + +from blog.documents import ArticleDocument, ArticleDocumentManager +from blog.models import Article + +logger = logging.getLogger(__name__) + + +class ElasticSearchBackend(BaseSearchBackend): + def __init__(self, connection_alias, **connection_options): + super( + ElasticSearchBackend, + self).__init__( + connection_alias, + **connection_options) + self.manager = ArticleDocumentManager() + self.include_spelling = True + + def _get_models(self, iterable): + models = iterable if iterable and iterable[0] else Article.objects.all() + docs = self.manager.convert_to_doc(models) + return docs + + def _create(self, models): + self.manager.create_index() + docs = self._get_models(models) + self.manager.rebuild(docs) + + def _delete(self, models): + for m in models: + m.delete() + return True + + def _rebuild(self, models): + models = models if models else Article.objects.all() + docs = self.manager.convert_to_doc(models) + self.manager.update_docs(docs) + + def update(self, index, iterable, commit=True): + + models = self._get_models(iterable) + self.manager.update_docs(models) + + def remove(self, obj_or_string): + models = self._get_models([obj_or_string]) + self._delete(models) + + def clear(self, models=None, commit=True): + self.remove(None) + + @staticmethod + def get_suggestion(query: str) -> str: + """获取推荐词, 如果没有找到添加原搜索词""" + + search = ArticleDocument.search() \ + .query("match", body=query) \ + .suggest('suggest_search', query, term={'field': 'body'}) \ + .execute() + + keywords = [] + for suggest in search.suggest.suggest_search: + if suggest["options"]: + keywords.append(suggest["options"][0]["text"]) + else: + keywords.append(suggest["text"]) + + return ' '.join(keywords) + + @log_query + def search(self, query_string, **kwargs): + logger.info('search query_string:' + query_string) + + start_offset = kwargs.get('start_offset') + end_offset = kwargs.get('end_offset') + + # 推荐词搜索 + if getattr(self, "is_suggest", None): + suggestion = self.get_suggestion(query_string) + else: + suggestion = query_string + + q = Q('bool', + should=[Q('match', body=suggestion), Q('match', title=suggestion)], + minimum_should_match="70%") + + search = ArticleDocument.search() \ + .query('bool', filter=[q]) \ + .filter('term', status='p') \ + .filter('term', type='a') \ + .source(False)[start_offset: end_offset] + + results = search.execute() + hits = results['hits'].total + raw_results = [] + for raw_result in results['hits']['hits']: + app_label = 'blog' + model_name = 'Article' + additional_fields = {} + + result_class = SearchResult + + result = result_class( + app_label, + model_name, + raw_result['_id'], + raw_result['_score'], + **additional_fields) + raw_results.append(result) + facets = {} + spelling_suggestion = None if query_string == suggestion else suggestion + + return { + 'results': raw_results, + 'hits': hits, + 'facets': facets, + 'spelling_suggestion': spelling_suggestion, + } + + +class ElasticSearchQuery(BaseSearchQuery): + def _convert_datetime(self, date): + if hasattr(date, 'hour'): + return force_str(date.strftime('%Y%m%d%H%M%S')) + else: + return force_str(date.strftime('%Y%m%d000000')) + + def clean(self, query_fragment): + """ + Provides a mechanism for sanitizing user input before presenting the + value to the backend. + + Whoosh 1.X differs here in that you can no longer use a backslash + to escape reserved characters. Instead, the whole word should be + quoted. + """ + words = query_fragment.split() + cleaned_words = [] + + for word in words: + if word in self.backend.RESERVED_WORDS: + word = word.replace(word, word.lower()) + + for char in self.backend.RESERVED_CHARACTERS: + if char in word: + word = "'%s'" % word + break + + cleaned_words.append(word) + + return ' '.join(cleaned_words) + + def build_query_fragment(self, field, filter_type, value): + return value.query_string + + def get_count(self): + results = self.get_results() + return len(results) if results else 0 + + def get_spelling_suggestion(self, preferred_query=None): + return self._spelling_suggestion + + def build_params(self, spelling_query=None): + kwargs = super(ElasticSearchQuery, self).build_params(spelling_query=spelling_query) + return kwargs + + +class ElasticSearchModelSearchForm(ModelSearchForm): + + def search(self): + # 是否建议搜索 + self.searchqueryset.query.backend.is_suggest = self.data.get("is_suggest") != "no" + sqs = super().search() + return sqs + + +class ElasticSearchEngine(BaseEngine): + backend = ElasticSearchBackend + query = ElasticSearchQuery diff --git a/djangoblog/feeds.py b/djangoblog/feeds.py new file mode 100644 index 0000000..8c4e851 --- /dev/null +++ b/djangoblog/feeds.py @@ -0,0 +1,40 @@ +from django.contrib.auth import get_user_model +from django.contrib.syndication.views import Feed +from django.utils import timezone +from django.utils.feedgenerator import Rss201rev2Feed + +from blog.models import Article +from djangoblog.utils import CommonMarkdown + + +class DjangoBlogFeed(Feed): + feed_type = Rss201rev2Feed + + description = '大巧无工,重剑无锋.' + title = "且听风吟 大巧无工,重剑无锋. " + link = "/feed/" + + def author_name(self): + return get_user_model().objects.first().nickname + + def author_link(self): + return get_user_model().objects.first().get_absolute_url() + + def items(self): + return Article.objects.filter(type='a', status='p').order_by('-pub_time')[:5] + + def item_title(self, item): + return item.title + + def item_description(self, item): + return CommonMarkdown.get_markdown(item.body) + + def feed_copyright(self): + now = timezone.now() + return "Copyright© {year} 且听风吟".format(year=now.year) + + def item_link(self, item): + return item.get_absolute_url() + + def item_guid(self, item): + return diff --git a/djangoblog/logentryadmin.py b/djangoblog/logentryadmin.py new file mode 100644 index 0000000..2f6a535 --- /dev/null +++ b/djangoblog/logentryadmin.py @@ -0,0 +1,91 @@ +from django.contrib import admin +from django.contrib.admin.models import DELETION +from django.contrib.contenttypes.models import ContentType +from django.urls import reverse, NoReverseMatch +from django.utils.encoding import force_str +from django.utils.html import escape +from django.utils.safestring import mark_safe +from django.utils.translation import gettext_lazy as _ + + +class LogEntryAdmin(admin.ModelAdmin): + list_filter = [ + 'content_type' + ] + + search_fields = [ + 'object_repr', + 'change_message' + ] + + list_display_links = [ + 'action_time', + 'get_change_message', + ] + list_display = [ + 'action_time', + 'user_link', + 'content_type', + 'object_link', + 'get_change_message', + ] + + def has_add_permission(self, request): + return False + + def has_change_permission(self, request, obj=None): + return ( + request.user.is_superuser or + request.user.has_perm('admin.change_logentry') + ) and request.method != 'POST' + + def has_delete_permission(self, request, obj=None): + return False + + def object_link(self, obj): + object_link = escape(obj.object_repr) + content_type = obj.content_type + + if obj.action_flag != DELETION and content_type is not None: + # try returning an actual link instead of object repr string + try: + url = reverse( + 'admin:{}_{}_change'.format(content_type.app_label, + content_type.model), + args=[obj.object_id] + ) + object_link = '{}'.format(url, object_link) + except NoReverseMatch: + pass + return mark_safe(object_link) + + object_link.admin_order_field = 'object_repr' + object_link.short_description = _('object') + + def user_link(self, obj): + content_type = ContentType.objects.get_for_model(type(obj.user)) + user_link = escape(force_str(obj.user)) + try: + # try returning an actual link instead of object repr string + url = reverse( + 'admin:{}_{}_change'.format(content_type.app_label, + content_type.model), + args=[obj.user.pk] + ) + user_link = '{}'.format(url, user_link) + except NoReverseMatch: + pass + return mark_safe(user_link) + + user_link.admin_order_field = 'user' + user_link.short_description = _('user') + + def get_queryset(self, request): + queryset = super(LogEntryAdmin, self).get_queryset(request) + return queryset.prefetch_related('content_type') + + def get_actions(self, request): + actions = super(LogEntryAdmin, self).get_actions(request) + if 'delete_selected' in actions: + del actions['delete_selected'] + return actions diff --git a/djangoblog/plugin_manage/base_plugin.py b/djangoblog/plugin_manage/base_plugin.py new file mode 100644 index 0000000..2b4be5c --- /dev/null +++ b/djangoblog/plugin_manage/base_plugin.py @@ -0,0 +1,41 @@ +import logging + +logger = logging.getLogger(__name__) + + +class BasePlugin: + # 插件元数据 + PLUGIN_NAME = None + PLUGIN_DESCRIPTION = None + PLUGIN_VERSION = None + + def __init__(self): + if not all([self.PLUGIN_NAME, self.PLUGIN_DESCRIPTION, self.PLUGIN_VERSION]): + raise ValueError("Plugin metadata (PLUGIN_NAME, PLUGIN_DESCRIPTION, PLUGIN_VERSION) must be defined.") + self.init_plugin() + self.register_hooks() + + def init_plugin(self): + """ + 插件初始化逻辑 + 子类可以重写此方法来实现特定的初始化操作 + """ + logger.info(f'{self.PLUGIN_NAME} initialized.') + + def register_hooks(self): + """ + 注册插件钩子 + 子类可以重写此方法来注册特定的钩子 + """ + pass + + def get_plugin_info(self): + """ + 获取插件信息 + :return: 包含插件元数据的字典 + """ + return { + 'name': self.PLUGIN_NAME, + 'description': self.PLUGIN_DESCRIPTION, + 'version': self.PLUGIN_VERSION + } diff --git a/djangoblog/plugin_manage/hook_constants.py b/djangoblog/plugin_manage/hook_constants.py new file mode 100644 index 0000000..6685b7c --- /dev/null +++ b/djangoblog/plugin_manage/hook_constants.py @@ -0,0 +1,7 @@ +ARTICLE_DETAIL_LOAD = 'article_detail_load' +ARTICLE_CREATE = 'article_create' +ARTICLE_UPDATE = 'article_update' +ARTICLE_DELETE = 'article_delete' + +ARTICLE_CONTENT_HOOK_NAME = "the_content" + diff --git a/djangoblog/plugin_manage/hooks.py b/djangoblog/plugin_manage/hooks.py new file mode 100644 index 0000000..d712540 --- /dev/null +++ b/djangoblog/plugin_manage/hooks.py @@ -0,0 +1,44 @@ +import logging + +logger = logging.getLogger(__name__) + +_hooks = {} + + +def register(hook_name: str, callback: callable): + """ + 注册一个钩子回调。 + """ + if hook_name not in _hooks: + _hooks[hook_name] = [] + _hooks[hook_name].append(callback) + logger.debug(f"Registered hook '{hook_name}' with callback '{callback.__name__}'") + + +def run_action(hook_name: str, *args, **kwargs): + """ + 执行一个 Action Hook。 + 它会按顺序执行所有注册到该钩子上的回调函数。 + """ + if hook_name in _hooks: + logger.debug(f"Running action hook '{hook_name}'") + for callback in _hooks[hook_name]: + try: + callback(*args, **kwargs) + except Exception as e: + logger.error(f"Error running action hook '{hook_name}' callback '{callback.__name__}': {e}", exc_info=True) + + +def apply_filters(hook_name: str, value, *args, **kwargs): + """ + 执行一个 Filter Hook。 + 它会把 value 依次传递给所有注册的回调函数进行处理。 + """ + if hook_name in _hooks: + logger.debug(f"Applying filter hook '{hook_name}'") + for callback in _hooks[hook_name]: + try: + value = callback(value, *args, **kwargs) + except Exception as e: + logger.error(f"Error applying filter hook '{hook_name}' callback '{callback.__name__}': {e}", exc_info=True) + return value diff --git a/djangoblog/plugin_manage/loader.py b/djangoblog/plugin_manage/loader.py new file mode 100644 index 0000000..12e824b --- /dev/null +++ b/djangoblog/plugin_manage/loader.py @@ -0,0 +1,19 @@ +import os +import logging +from django.conf import settings + +logger = logging.getLogger(__name__) + +def load_plugins(): + """ + Dynamically loads and initializes plugins from the 'plugins' directory. + This function is intended to be called when the Django app registry is ready. + """ + for plugin_name in settings.ACTIVE_PLUGINS: + plugin_path = os.path.join(settings.PLUGINS_DIR, plugin_name) + if os.path.isdir(plugin_path) and os.path.exists(os.path.join(plugin_path, 'plugin.py')): + try: + __import__(f'plugins.{plugin_name}.plugin') + logger.info(f"Successfully loaded plugin: {plugin_name}") + except ImportError as e: + logger.error(f"Failed to import plugin: {plugin_name}", exc_info=e) \ No newline at end of file diff --git a/djangoblog/settings.py b/djangoblog/settings.py new file mode 100644 index 0000000..d076bb6 --- /dev/null +++ b/djangoblog/settings.py @@ -0,0 +1,343 @@ +""" +Django settings for djangoblog project. + +Generated by 'django-admin startproject' using Django 1.10.2. + +For more information on this file, see +https://docs.djangoproject.com/en/1.10/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/1.10/ref/settings/ +""" +import os +import sys +from pathlib import Path + +from django.utils.translation import gettext_lazy as _ + + +def env_to_bool(env, default): + str_val = os.environ.get(env) + return default if str_val is None else str_val == 'True' + + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = os.environ.get( + 'DJANGO_SECRET_KEY') or 'n9ceqv38)#&mwuat@(mjb_p%em$e8$qyr#fw9ot!=ba6lijx-6' +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = env_to_bool('DJANGO_DEBUG', True) +# DEBUG = False +TESTING = len(sys.argv) > 1 and sys.argv[1] == 'test' + +# ALLOWED_HOSTS = [] +ALLOWED_HOSTS = ['*', '127.0.0.1', 'example.com'] +# django 4.0新增配置 +CSRF_TRUSTED_ORIGINS = ['http://example.com'] +# Application definition + + +INSTALLED_APPS = [ + # 'django.contrib.admin', + 'django.contrib.admin.apps.SimpleAdminConfig', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'django.contrib.sites', + 'django.contrib.sitemaps', + 'mdeditor', + 'haystack', + 'blog', + 'accounts', + 'comments', + 'oauth', + 'servermanager', + 'owntracks', + 'compressor', + 'djangoblog' +] + +MIDDLEWARE = [ + + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.locale.LocaleMiddleware', + 'django.middleware.gzip.GZipMiddleware', + # 'django.middleware.cache.UpdateCacheMiddleware', + 'django.middleware.common.CommonMiddleware', + # 'django.middleware.cache.FetchFromCacheMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'django.middleware.http.ConditionalGetMiddleware', + 'blog.middleware.OnlineMiddleware' +] + +ROOT_URLCONF = 'djangoblog.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [os.path.join(BASE_DIR, 'templates')], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + 'blog.context_processors.seo_processor' + ], + }, + }, +] + +WSGI_APPLICATION = 'djangoblog.wsgi.application' + +# Database +# https://docs.djangoproject.com/en/1.10/ref/settings/#databases + + +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', + 'PORT': int( + os.environ.get('DJANGO_MYSQL_PORT') or 3306), + 'OPTIONS': { + 'charset': 'utf8mb4'}, + }} + +# Password validation +# https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + +LANGUAGES = ( + ('en', _('English')), + ('zh-hans', _('Simplified Chinese')), + ('zh-hant', _('Traditional Chinese')), +) +LOCALE_PATHS = ( + os.path.join(BASE_DIR, 'locale'), +) + +LANGUAGE_CODE = 'zh-hans' + +TIME_ZONE = 'Asia/Shanghai' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = False + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/1.10/howto/static-files/ + + +HAYSTACK_CONNECTIONS = { + 'default': { + 'ENGINE': 'djangoblog.whoosh_cn_backend.WhooshEngine', + 'PATH': os.path.join(os.path.dirname(__file__), 'whoosh_index'), + }, +} +# Automatically update searching index +HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor' +# Allow user login with username and password +AUTHENTICATION_BACKENDS = [ + 'accounts.user_login_backend.EmailOrUsernameModelBackend'] + +STATIC_ROOT = os.path.join(BASE_DIR, 'collectedstatic') + +STATIC_URL = '/static/' +STATICFILES = os.path.join(BASE_DIR, 'static') + +AUTH_USER_MODEL = 'accounts.BlogUser' +LOGIN_URL = '/login/' + +TIME_FORMAT = '%Y-%m-%d %H:%M:%S' +DATE_TIME_FORMAT = '%Y-%m-%d' + +# bootstrap color styles +BOOTSTRAP_COLOR_TYPES = [ + 'default', 'primary', 'success', 'info', 'warning', 'danger' +] + +# paginate +PAGINATE_BY = 10 +# http cache timeout +CACHE_CONTROL_MAX_AGE = 2592000 +# cache setting +CACHES = { + 'default': { + 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', + 'TIMEOUT': 10800, + 'LOCATION': 'unique-snowflake', + } +} +# 使用redis作为缓存 +if os.environ.get("DJANGO_REDIS_URL"): + CACHES = { + 'default': { + 'BACKEND': 'django.core.cache.backends.redis.RedisCache', + 'LOCATION': f'redis://{os.environ.get("DJANGO_REDIS_URL")}', + } + } + +SITE_ID = 1 +BAIDU_NOTIFY_URL = os.environ.get('DJANGO_BAIDU_NOTIFY_URL') \ + or 'http://data.zz.baidu.com/urls?site=https://www.lylinux.net&token=1uAOGrMsUm5syDGn' + +# Email: +EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' +EMAIL_USE_TLS = env_to_bool('DJANGO_EMAIL_TLS', False) +EMAIL_USE_SSL = env_to_bool('DJANGO_EMAIL_SSL', True) +EMAIL_HOST = os.environ.get('DJANGO_EMAIL_HOST') or 'smtp.mxhichina.com' +EMAIL_PORT = int(os.environ.get('DJANGO_EMAIL_PORT') or 465) +EMAIL_HOST_USER = os.environ.get('DJANGO_EMAIL_USER') +EMAIL_HOST_PASSWORD = os.environ.get('DJANGO_EMAIL_PASSWORD') +DEFAULT_FROM_EMAIL = EMAIL_HOST_USER +SERVER_EMAIL = EMAIL_HOST_USER +# Setting debug=false did NOT handle except email notifications +ADMINS = [('admin', os.environ.get('DJANGO_ADMIN_EMAIL') or 'admin@admin.com')] +# WX ADMIN password(Two times md5) +WXADMIN = os.environ.get( + 'DJANGO_WXADMIN_PASSWORD') or '995F03AC401D6CABABAEF756FC4D43C7' + +LOG_PATH = os.path.join(BASE_DIR, 'logs') +if not os.path.exists(LOG_PATH): + os.makedirs(LOG_PATH, exist_ok=True) + +LOGGING = { + 'version': 1, + 'disable_existing_loggers': False, + 'root': { + 'level': 'INFO', + 'handlers': ['console', 'log_file'], + }, + 'formatters': { + 'verbose': { + 'format': '[%(asctime)s] %(levelname)s [%(name)s.%(funcName)s:%(lineno)d %(module)s] %(message)s', + } + }, + 'filters': { + 'require_debug_false': { + '()': 'django.utils.log.RequireDebugFalse', + }, + 'require_debug_true': { + '()': 'django.utils.log.RequireDebugTrue', + }, + }, + 'handlers': { + 'log_file': { + 'level': 'INFO', + 'class': 'logging.handlers.TimedRotatingFileHandler', + 'filename': os.path.join(LOG_PATH, 'djangoblog.log'), + 'when': 'D', + 'formatter': 'verbose', + 'interval': 1, + 'delay': True, + 'backupCount': 5, + 'encoding': 'utf-8' + }, + 'console': { + 'level': 'DEBUG', + 'filters': ['require_debug_true'], + 'class': 'logging.StreamHandler', + 'formatter': 'verbose' + }, + 'null': { + 'class': 'logging.NullHandler', + }, + 'mail_admins': { + 'level': 'ERROR', + 'filters': ['require_debug_false'], + 'class': 'django.utils.log.AdminEmailHandler' + } + }, + 'loggers': { + 'djangoblog': { + 'handlers': ['log_file', 'console'], + 'level': 'INFO', + 'propagate': True, + }, + 'django.request': { + 'handlers': ['mail_admins'], + 'level': 'ERROR', + 'propagate': False, + } + } +} + +STATICFILES_FINDERS = ( + 'django.contrib.staticfiles.finders.FileSystemFinder', + 'django.contrib.staticfiles.finders.AppDirectoriesFinder', + # other + 'compressor.finders.CompressorFinder', +) +COMPRESS_ENABLED = True +# COMPRESS_OFFLINE = True + + +COMPRESS_CSS_FILTERS = [ + # creates absolute urls from relative ones + 'compressor.filters.css_default.CssAbsoluteFilter', + # css minimizer + 'compressor.filters.cssmin.CSSMinFilter' +] +COMPRESS_JS_FILTERS = [ + 'compressor.filters.jsmin.JSMinFilter' +] + +MEDIA_ROOT = os.path.join(BASE_DIR, 'uploads') +MEDIA_URL = '/media/' +X_FRAME_OPTIONS = 'SAMEORIGIN' + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + +if os.environ.get('DJANGO_ELASTICSEARCH_HOST'): + ELASTICSEARCH_DSL = { + 'default': { + 'hosts': os.environ.get('DJANGO_ELASTICSEARCH_HOST') + }, + } + HAYSTACK_CONNECTIONS = { + 'default': { + 'ENGINE': 'djangoblog.elasticsearch_backend.ElasticSearchEngine', + }, + } + +# Plugin System +PLUGINS_DIR = BASE_DIR / 'plugins' +ACTIVE_PLUGINS = [ + 'article_copyright', + 'reading_time', + 'external_links', + 'view_count', + 'seo_optimizer' +] \ No newline at end of file diff --git a/djangoblog/sitemap.py b/djangoblog/sitemap.py new file mode 100644 index 0000000..8b7d446 --- /dev/null +++ b/djangoblog/sitemap.py @@ -0,0 +1,59 @@ +from django.contrib.sitemaps import Sitemap +from django.urls import reverse + +from blog.models import Article, Category, Tag + + +class StaticViewSitemap(Sitemap): + priority = 0.5 + changefreq = 'daily' + + def items(self): + return ['blog:index', ] + + def location(self, item): + return reverse(item) + + +class ArticleSiteMap(Sitemap): + changefreq = "monthly" + priority = "0.6" + + def items(self): + return Article.objects.filter(status='p') + + def lastmod(self, obj): + return obj.last_modify_time + + +class CategorySiteMap(Sitemap): + changefreq = "Weekly" + priority = "0.6" + + def items(self): + return Category.objects.all() + + def lastmod(self, obj): + return obj.last_modify_time + + +class TagSiteMap(Sitemap): + changefreq = "Weekly" + priority = "0.3" + + def items(self): + return Tag.objects.all() + + def lastmod(self, obj): + return obj.last_modify_time + + +class UserSiteMap(Sitemap): + changefreq = "Weekly" + priority = "0.3" + + def items(self): + return list(set(map(lambda x: x.author, Article.objects.all()))) + + def lastmod(self, obj): + return obj.date_joined diff --git a/djangoblog/spider_notify.py b/djangoblog/spider_notify.py new file mode 100644 index 0000000..7b909e9 --- /dev/null +++ b/djangoblog/spider_notify.py @@ -0,0 +1,21 @@ +import logging + +import requests +from django.conf import settings + +logger = logging.getLogger(__name__) + + +class SpiderNotify(): + @staticmethod + def baidu_notify(urls): + try: + data = '\n'.join(urls) + result = requests.post(settings.BAIDU_NOTIFY_URL, data=data) + logger.info(result.text) + except Exception as e: + logger.error(e) + + @staticmethod + def notify(url): + SpiderNotify.baidu_notify(url) diff --git a/djangoblog/tests.py b/djangoblog/tests.py new file mode 100644 index 0000000..01237d9 --- /dev/null +++ b/djangoblog/tests.py @@ -0,0 +1,32 @@ +from django.test import TestCase + +from djangoblog.utils import * + + +class DjangoBlogTest(TestCase): + def setUp(self): + pass + + def test_utils(self): + md5 = get_sha256('test') + self.assertIsNotNone(md5) + c = CommonMarkdown.get_markdown(''' + # Title1 + + ```python + import os + ``` + + [url](https://www.lylinux.net/) + + [ddd](http://www.baidu.com) + + + ''') + self.assertIsNotNone(c) + d = { + 'd': 'key1', + 'd2': 'key2' + } + data = parse_dict_to_url(d) + self.assertIsNotNone(data) diff --git a/djangoblog/urls.py b/djangoblog/urls.py new file mode 100644 index 0000000..4aae58a --- /dev/null +++ b/djangoblog/urls.py @@ -0,0 +1,64 @@ +"""djangoblog URL Configuration + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/1.10/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') +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')) +""" +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.urls import path, include +from django.urls import re_path +from haystack.views import search_view_factory + +from blog.views import EsSearchView +from djangoblog.admin_site import admin_site +from djangoblog.elasticsearch_backend import ElasticSearchModelSearchForm +from djangoblog.feeds import DjangoBlogFeed +from djangoblog.sitemap import ArticleSiteMap, CategorySiteMap, StaticViewSitemap, TagSiteMap, UserSiteMap + +sitemaps = { + + 'blog': ArticleSiteMap, + 'Category': CategorySiteMap, + 'Tag': TagSiteMap, + 'User': UserSiteMap, + 'static': StaticViewSitemap +} + +handler404 = 'blog.views.page_not_found_view' +handler500 = 'blog.views.server_error_view' +handle403 = 'blog.views.permission_denied_view' + +urlpatterns = [ + path('i18n/', include('django.conf.urls.i18n')), +] +urlpatterns += i18n_patterns( + re_path(r'^admin/', admin_site.urls), + re_path(r'', include('blog.urls', namespace='blog')), + re_path(r'mdeditor/', include('mdeditor.urls')), + re_path(r'', include('comments.urls', namespace='comment')), + re_path(r'', include('accounts.urls', namespace='account')), + re_path(r'', include('oauth.urls', namespace='oauth')), + re_path(r'^sitemap\.xml$', sitemap, {'sitemaps': sitemaps}, + name='django.contrib.sitemaps.views.sitemap'), + re_path(r'^feed/$', DjangoBlogFeed()), + re_path(r'^rss/$', DjangoBlogFeed()), + re_path('^search', search_view_factory(view_class=EsSearchView, form_class=ElasticSearchModelSearchForm), + name='search'), + re_path(r'', include('servermanager.urls', namespace='servermanager')), + re_path(r'', include('owntracks.urls', namespace='owntracks')) + , prefix_default_language=False) + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) +if settings.DEBUG: + urlpatterns += static(settings.MEDIA_URL, + document_root=settings.MEDIA_ROOT) diff --git a/djangoblog/utils.py b/djangoblog/utils.py new file mode 100644 index 0000000..57f63dc --- /dev/null +++ b/djangoblog/utils.py @@ -0,0 +1,232 @@ +#!/usr/bin/env python +# encoding: utf-8 + + +import logging +import os +import random +import string +import uuid +from hashlib import sha256 + +import bleach +import markdown +import requests +from django.conf import settings +from django.contrib.sites.models import Site +from django.core.cache import cache +from django.templatetags.static import static + +logger = logging.getLogger(__name__) + + +def get_max_articleid_commentid(): + from blog.models import Article + from comments.models import Comment + return (Article.objects.latest().pk, Comment.objects.latest().pk) + + +def get_sha256(str): + m = sha256(str.encode('utf-8')) + return m.hexdigest() + + +def cache_decorator(expiration=3 * 60): + def wrapper(func): + def news(*args, **kwargs): + try: + view = args[0] + key = view.get_cache_key() + except: + key = None + if not key: + unique_str = repr((func, args, kwargs)) + + m = sha256(unique_str.encode('utf-8')) + key = m.hexdigest() + value = cache.get(key) + if value is not None: + # logger.info('cache_decorator get cache:%s key:%s' % (func.__name__, key)) + if str(value) == '__default_cache_value__': + return None + else: + return value + else: + logger.debug( + 'cache_decorator set cache:%s key:%s' % + (func.__name__, key)) + value = func(*args, **kwargs) + if value is None: + cache.set(key, '__default_cache_value__', expiration) + else: + cache.set(key, value, expiration) + return value + + return news + + return wrapper + + +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 + + request = HttpRequest() + request.META = {'SERVER_NAME': servername, 'SERVER_PORT': serverport} + request.path = path + + key = get_cache_key(request, key_prefix=key_prefix, cache=cache) + if key: + logger.info('expire_view_cache:get key:{path}'.format(path=path)) + if cache.get(key): + cache.delete(key) + return True + return False + + +@cache_decorator() +def get_current_site(): + site = Site.objects.get_current() + return site + + +class CommonMarkdown: + @staticmethod + def _convert_markdown(value): + md = markdown.Markdown( + extensions=[ + 'extra', + 'codehilite', + 'toc', + 'tables', + ] + ) + body = md.convert(value) + toc = md.toc + return body, toc + + @staticmethod + def get_markdown_with_toc(value): + body, toc = CommonMarkdown._convert_markdown(value) + return body, toc + + @staticmethod + def get_markdown(value): + body, toc = CommonMarkdown._convert_markdown(value) + return body + + +def send_email(emailto, title, content): + from djangoblog.blog_signals import send_email_signal + send_email_signal.send( + send_email.__class__, + emailto=emailto, + title=title, + content=content) + + +def generate_code() -> str: + """生成随机数验证码""" + return ''.join(random.sample(string.digits, 6)) + + +def parse_dict_to_url(dict): + from urllib.parse import quote + url = '&'.join(['{}={}'.format(quote(k, safe='/'), quote(v, safe='/')) + for k, v in dict.items()]) + return url + + +def get_blog_setting(): + value = cache.get('get_blog_setting') + if value: + return value + else: + from blog.models import BlogSettings + if not BlogSettings.objects.count(): + setting = BlogSettings() + setting.site_name = 'djangoblog' + setting.site_description = '基于Django的博客系统' + setting.site_seo_description = '基于Django的博客系统' + setting.site_keywords = 'Django,Python' + setting.article_sub_length = 300 + setting.sidebar_article_count = 10 + setting.sidebar_comment_count = 5 + setting.show_google_adsense = False + setting.open_site_comment = True + setting.analytics_code = '' + setting.beian_code = '' + setting.show_gongan_code = False + setting.comment_need_review = False + setting.save() + value = BlogSettings.objects.first() + logger.info('set cache get_blog_setting') + cache.set('get_blog_setting', value) + return value + + +def save_user_avatar(url): + ''' + 保存用户头像 + :param url:头像url + :return: 本地路径 + ''' + logger.info(url) + + try: + basedir = os.path.join(settings.STATICFILES, 'avatar') + rsp = requests.get(url, timeout=2) + if rsp.status_code == 200: + if not os.path.exists(basedir): + os.makedirs(basedir) + + image_extensions = ['.jpg', '.png', 'jpeg', '.gif'] + isimage = len([i for i in image_extensions if url.endswith(i)]) > 0 + ext = os.path.splitext(url)[1] if isimage else '.jpg' + save_filename = str(uuid.uuid4().hex) + ext + logger.info('保存用户头像:' + basedir + save_filename) + with open(os.path.join(basedir, save_filename), 'wb+') as file: + file.write(rsp.content) + return static('avatar/' + save_filename) + except Exception as e: + logger.error(e) + return static('blog/img/avatar.png') + + +def delete_sidebar_cache(): + from blog.models import LinkShowType + keys = ["sidebar" + x for x in LinkShowType.values] + for k in keys: + logger.info('delete sidebar key:' + k) + cache.delete(k) + + +def delete_view_cache(prefix, keys): + from django.core.cache.utils import make_template_fragment_key + key = make_template_fragment_key(prefix, keys) + cache.delete(key) + + +def get_resource_url(): + if settings.STATIC_URL: + return settings.STATIC_URL + else: + site = get_current_site() + return 'http://' + site.domain + '/static/' + + +ALLOWED_TAGS = ['a', 'abbr', 'acronym', 'b', 'blockquote', 'code', 'em', 'i', 'li', 'ol', 'pre', 'strong', 'ul', 'h1', + 'h2', 'p'] +ALLOWED_ATTRIBUTES = {'a': ['href', 'title'], 'abbr': ['title'], 'acronym': ['title']} + + +def sanitize_html(html): + return bleach.clean(html, tags=ALLOWED_TAGS, attributes=ALLOWED_ATTRIBUTES) diff --git a/djangoblog/whoosh_cn_backend.py b/djangoblog/whoosh_cn_backend.py new file mode 100644 index 0000000..04e3f7f --- /dev/null +++ b/djangoblog/whoosh_cn_backend.py @@ -0,0 +1,1044 @@ +# encoding: utf-8 + +from __future__ import absolute_import, division, print_function, unicode_literals + +import json +import os +import re +import shutil +import threading +import warnings + +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 +from haystack.exceptions import MissingDependency, SearchBackendError, SkipDocument +from haystack.inputs import Clean, Exact, PythonData, Raw +from haystack.models import SearchResult +from haystack.utils import get_identifier, get_model_ct +from haystack.utils import log as logging +from haystack.utils.app_loading import haystack_get_model +from jieba.analyse import ChineseAnalyzer +from whoosh import index +from whoosh.analysis import StemmingAnalyzer +from whoosh.fields import BOOLEAN, DATETIME, IDLIST, KEYWORD, NGRAM, NGRAMWORDS, NUMERIC, Schema, TEXT +from whoosh.fields import ID as WHOOSH_ID +from whoosh.filedb.filestore import FileStorage, RamStorage +from whoosh.highlight import ContextFragmenter, HtmlFormatter +from whoosh.highlight import highlight as whoosh_highlight +from whoosh.qparser import QueryParser +from whoosh.searching import ResultsPage +from whoosh.writing import AsyncWriter + +try: + import whoosh +except ImportError: + raise MissingDependency( + "The 'whoosh' backend requires the installation of 'Whoosh'. Please refer to the documentation.") + +# Handle minimum requirement. +if not hasattr(whoosh, '__version__') or whoosh.__version__ < (2, 5, 0): + raise MissingDependency( + "The 'whoosh' backend requires version 2.5.0 or greater.") + +# Bubble up the correct error. + +DATETIME_REGEX = re.compile( + '^(?P\d{4})-(?P\d{2})-(?P\d{2})T(?P\d{2}):(?P\d{2}):(?P\d{2})(\.\d{3,6}Z?)?$') +LOCALS = threading.local() +LOCALS.RAM_STORE = None + + +class WhooshHtmlFormatter(HtmlFormatter): + """ + This is a HtmlFormatter simpler than the whoosh.HtmlFormatter. + We use it to have consistent results across backends. Specifically, + Solr, Xapian and Elasticsearch are using this formatting. + """ + template = '<%(tag)s>%(t)s' + + +class WhooshSearchBackend(BaseSearchBackend): + # Word reserved by Whoosh for special use. + RESERVED_WORDS = ( + 'AND', + 'NOT', + 'OR', + 'TO', + ) + + # Characters reserved by Whoosh for special use. + # The '\\' must come first, so as not to overwrite the other slash + # replacements. + RESERVED_CHARACTERS = ( + '\\', '+', '-', '&&', '||', '!', '(', ')', '{', '}', + '[', ']', '^', '"', '~', '*', '?', ':', '.', + ) + + def __init__(self, connection_alias, **connection_options): + super( + WhooshSearchBackend, + self).__init__( + connection_alias, + **connection_options) + self.setup_complete = False + self.use_file_storage = True + self.post_limit = getattr( + connection_options, + 'POST_LIMIT', + 128 * 1024 * 1024) + self.path = connection_options.get('PATH') + + if connection_options.get('STORAGE', 'file') != 'file': + self.use_file_storage = False + + if self.use_file_storage and not self.path: + raise ImproperlyConfigured( + "You must specify a 'PATH' in your settings for connection '%s'." % + connection_alias) + + self.log = logging.getLogger('haystack') + + def setup(self): + """ + Defers loading until needed. + """ + from haystack import connections + new_index = False + + # Make sure the index is there. + if self.use_file_storage and not os.path.exists(self.path): + os.makedirs(self.path) + new_index = True + + if self.use_file_storage and not os.access(self.path, os.W_OK): + raise IOError( + "The path to your Whoosh index '%s' is not writable for the current user/group." % + self.path) + + if self.use_file_storage: + self.storage = FileStorage(self.path) + else: + global LOCALS + + if getattr(LOCALS, 'RAM_STORE', None) is None: + LOCALS.RAM_STORE = RamStorage() + + self.storage = LOCALS.RAM_STORE + + self.content_field_name, self.schema = self.build_schema( + connections[self.connection_alias].get_unified_index().all_searchfields()) + self.parser = QueryParser(self.content_field_name, schema=self.schema) + + if new_index is True: + self.index = self.storage.create_index(self.schema) + else: + try: + self.index = self.storage.open_index(schema=self.schema) + except index.EmptyIndexError: + self.index = self.storage.create_index(self.schema) + + self.setup_complete = True + + def build_schema(self, fields): + schema_fields = { + ID: WHOOSH_ID(stored=True, unique=True), + DJANGO_CT: WHOOSH_ID(stored=True), + DJANGO_ID: WHOOSH_ID(stored=True), + } + # Grab the number of keys that are hard-coded into Haystack. + # We'll use this to (possibly) fail slightly more gracefully later. + initial_key_count = len(schema_fields) + content_field_name = '' + + for field_name, field_class in fields.items(): + if field_class.is_multivalued: + if field_class.indexed is False: + schema_fields[field_class.index_fieldname] = IDLIST( + stored=True, field_boost=field_class.boost) + else: + schema_fields[field_class.index_fieldname] = KEYWORD( + stored=True, commas=True, scorable=True, field_boost=field_class.boost) + elif field_class.field_type in ['date', 'datetime']: + schema_fields[field_class.index_fieldname] = DATETIME( + stored=field_class.stored, sortable=True) + elif field_class.field_type == 'integer': + schema_fields[field_class.index_fieldname] = NUMERIC( + stored=field_class.stored, numtype=int, field_boost=field_class.boost) + elif field_class.field_type == 'float': + schema_fields[field_class.index_fieldname] = NUMERIC( + stored=field_class.stored, numtype=float, field_boost=field_class.boost) + elif field_class.field_type == 'boolean': + # Field boost isn't supported on BOOLEAN as of 1.8.2. + schema_fields[field_class.index_fieldname] = BOOLEAN( + stored=field_class.stored) + elif field_class.field_type == 'ngram': + schema_fields[field_class.index_fieldname] = NGRAM( + minsize=3, maxsize=15, stored=field_class.stored, field_boost=field_class.boost) + elif field_class.field_type == 'edge_ngram': + schema_fields[field_class.index_fieldname] = NGRAMWORDS(minsize=2, maxsize=15, at='start', + stored=field_class.stored, + field_boost=field_class.boost) + else: + # schema_fields[field_class.index_fieldname] = TEXT(stored=True, analyzer=StemmingAnalyzer(), field_boost=field_class.boost, sortable=True) + schema_fields[field_class.index_fieldname] = TEXT( + stored=True, analyzer=ChineseAnalyzer(), field_boost=field_class.boost, sortable=True) + if field_class.document is True: + content_field_name = field_class.index_fieldname + schema_fields[field_class.index_fieldname].spelling = True + + # Fail more gracefully than relying on the backend to die if no fields + # are found. + if len(schema_fields) <= initial_key_count: + raise SearchBackendError( + "No fields were found in any search_indexes. Please correct this before attempting to search.") + + return (content_field_name, Schema(**schema_fields)) + + def update(self, index, iterable, commit=True): + if not self.setup_complete: + self.setup() + + self.index = self.index.refresh() + writer = AsyncWriter(self.index) + + for obj in iterable: + try: + doc = index.full_prepare(obj) + except SkipDocument: + self.log.debug(u"Indexing for object `%s` skipped", obj) + else: + # Really make sure it's unicode, because Whoosh won't have it any + # other way. + for key in doc: + doc[key] = self._from_python(doc[key]) + + # Document boosts aren't supported in Whoosh 2.5.0+. + if 'boost' in doc: + del doc['boost'] + + try: + writer.update_document(**doc) + except Exception as e: + if not self.silently_fail: + raise + + # We'll log the object identifier but won't include the actual object + # to avoid the possibility of that generating encoding errors while + # processing the log message: + self.log.error( + u"%s while preparing object for update" % + e.__class__.__name__, + exc_info=True, + extra={ + "data": { + "index": index, + "object": get_identifier(obj)}}) + + if len(iterable) > 0: + # For now, commit no matter what, as we run into locking issues + # otherwise. + writer.commit() + + def remove(self, obj_or_string, commit=True): + if not self.setup_complete: + self.setup() + + self.index = self.index.refresh() + whoosh_id = get_identifier(obj_or_string) + + try: + self.index.delete_by_query( + q=self.parser.parse( + u'%s:"%s"' % + (ID, whoosh_id))) + except Exception as e: + if not self.silently_fail: + raise + + self.log.error( + "Failed to remove document '%s' from Whoosh: %s", + whoosh_id, + e, + exc_info=True) + + def clear(self, models=None, commit=True): + if not self.setup_complete: + self.setup() + + self.index = self.index.refresh() + + if models is not None: + assert isinstance(models, (list, tuple)) + + try: + if models is None: + self.delete_index() + else: + models_to_delete = [] + + for model in models: + models_to_delete.append( + u"%s:%s" % + (DJANGO_CT, get_model_ct(model))) + + self.index.delete_by_query( + q=self.parser.parse( + u" OR ".join(models_to_delete))) + except Exception as e: + if not self.silently_fail: + raise + + if models is not None: + self.log.error( + "Failed to clear Whoosh index of models '%s': %s", + ','.join(models_to_delete), + e, + exc_info=True) + else: + self.log.error( + "Failed to clear Whoosh index: %s", e, exc_info=True) + + def delete_index(self): + # Per the Whoosh mailing list, if wiping out everything from the index, + # it's much more efficient to simply delete the index files. + if self.use_file_storage and os.path.exists(self.path): + shutil.rmtree(self.path) + elif not self.use_file_storage: + self.storage.clean() + + # Recreate everything. + self.setup() + + def optimize(self): + if not self.setup_complete: + self.setup() + + self.index = self.index.refresh() + self.index.optimize() + + def calculate_page(self, start_offset=0, end_offset=None): + # Prevent against Whoosh throwing an error. Requires an end_offset + # greater than 0. + if end_offset is not None and end_offset <= 0: + end_offset = 1 + + # Determine the page. + page_num = 0 + + if end_offset is None: + end_offset = 1000000 + + if start_offset is None: + start_offset = 0 + + page_length = end_offset - start_offset + + if page_length and page_length > 0: + page_num = int(start_offset / page_length) + + # Increment because Whoosh uses 1-based page numbers. + page_num += 1 + return page_num, page_length + + @log_query + def search( + self, + query_string, + sort_by=None, + start_offset=0, + end_offset=None, + fields='', + highlight=False, + facets=None, + date_facets=None, + query_facets=None, + narrow_queries=None, + spelling_query=None, + within=None, + dwithin=None, + distance_point=None, + models=None, + limit_to_registered_models=None, + result_class=None, + **kwargs): + if not self.setup_complete: + self.setup() + + # A zero length query should return no results. + if len(query_string) == 0: + return { + 'results': [], + 'hits': 0, + } + + query_string = force_str(query_string) + + # A one-character query (non-wildcard) gets nabbed by a stopwords + # filter and should yield zero results. + if len(query_string) <= 1 and query_string != u'*': + return { + 'results': [], + 'hits': 0, + } + + reverse = False + + if sort_by is not None: + # Determine if we need to reverse the results and if Whoosh can + # handle what it's being asked to sort by. Reversing is an + # all-or-nothing action, unfortunately. + sort_by_list = [] + reverse_counter = 0 + + for order_by in sort_by: + if order_by.startswith('-'): + reverse_counter += 1 + + if reverse_counter and reverse_counter != len(sort_by): + raise SearchBackendError("Whoosh requires all order_by fields" + " to use the same sort direction") + + for order_by in sort_by: + if order_by.startswith('-'): + sort_by_list.append(order_by[1:]) + + if len(sort_by_list) == 1: + reverse = True + else: + sort_by_list.append(order_by) + + if len(sort_by_list) == 1: + reverse = False + + sort_by = sort_by_list[0] + + if facets is not None: + warnings.warn( + "Whoosh does not handle faceting.", + Warning, + stacklevel=2) + + if date_facets is not None: + warnings.warn( + "Whoosh does not handle date faceting.", + Warning, + stacklevel=2) + + if query_facets is not None: + warnings.warn( + "Whoosh does not handle query faceting.", + Warning, + stacklevel=2) + + narrowed_results = None + self.index = self.index.refresh() + + if limit_to_registered_models is None: + limit_to_registered_models = getattr( + settings, 'HAYSTACK_LIMIT_TO_REGISTERED_MODELS', True) + + if models and len(models): + model_choices = sorted(get_model_ct(model) for model in models) + elif limit_to_registered_models: + # Using narrow queries, limit the results to only models handled + # with the current routers. + model_choices = self.build_models_list() + else: + model_choices = [] + + if len(model_choices) > 0: + if narrow_queries is None: + narrow_queries = set() + + narrow_queries.add(' OR '.join( + ['%s:%s' % (DJANGO_CT, rm) for rm in model_choices])) + + narrow_searcher = None + + if narrow_queries is not None: + # Potentially expensive? I don't see another way to do it in + # Whoosh... + narrow_searcher = self.index.searcher() + + for nq in narrow_queries: + recent_narrowed_results = narrow_searcher.search( + self.parser.parse(force_str(nq)), limit=None) + + if len(recent_narrowed_results) <= 0: + return { + 'results': [], + 'hits': 0, + } + + if narrowed_results: + narrowed_results.filter(recent_narrowed_results) + else: + narrowed_results = recent_narrowed_results + + self.index = self.index.refresh() + + if self.index.doc_count(): + searcher = self.index.searcher() + parsed_query = self.parser.parse(query_string) + + # In the event of an invalid/stopworded query, recover gracefully. + if parsed_query is None: + return { + 'results': [], + 'hits': 0, + } + + page_num, page_length = self.calculate_page( + start_offset, end_offset) + + search_kwargs = { + 'pagelen': page_length, + 'sortedby': sort_by, + 'reverse': reverse, + } + + # Handle the case where the results have been narrowed. + if narrowed_results is not None: + search_kwargs['filter'] = narrowed_results + + try: + raw_page = searcher.search_page( + parsed_query, + page_num, + **search_kwargs + ) + except ValueError: + if not self.silently_fail: + raise + + return { + 'results': [], + 'hits': 0, + 'spelling_suggestion': None, + } + + # Because as of Whoosh 2.5.1, it will return the wrong page of + # results if you request something too high. :( + if raw_page.pagenum < page_num: + return { + 'results': [], + 'hits': 0, + 'spelling_suggestion': None, + } + + results = self._process_results( + raw_page, + highlight=highlight, + query_string=query_string, + spelling_query=spelling_query, + result_class=result_class) + searcher.close() + + if hasattr(narrow_searcher, 'close'): + narrow_searcher.close() + + return results + else: + if self.include_spelling: + if spelling_query: + spelling_suggestion = self.create_spelling_suggestion( + spelling_query) + else: + spelling_suggestion = self.create_spelling_suggestion( + query_string) + else: + spelling_suggestion = None + + return { + 'results': [], + 'hits': 0, + 'spelling_suggestion': spelling_suggestion, + } + + def more_like_this( + self, + model_instance, + additional_query_string=None, + start_offset=0, + end_offset=None, + models=None, + limit_to_registered_models=None, + result_class=None, + **kwargs): + if not self.setup_complete: + self.setup() + + # Deferred models will have a different class ("RealClass_Deferred_fieldname") + # which won't be in our registry: + model_klass = model_instance._meta.concrete_model + + field_name = self.content_field_name + narrow_queries = set() + narrowed_results = None + self.index = self.index.refresh() + + if limit_to_registered_models is None: + limit_to_registered_models = getattr( + settings, 'HAYSTACK_LIMIT_TO_REGISTERED_MODELS', True) + + if models and len(models): + model_choices = sorted(get_model_ct(model) for model in models) + elif limit_to_registered_models: + # Using narrow queries, limit the results to only models handled + # with the current routers. + model_choices = self.build_models_list() + else: + model_choices = [] + + if len(model_choices) > 0: + if narrow_queries is None: + narrow_queries = set() + + narrow_queries.add(' OR '.join( + ['%s:%s' % (DJANGO_CT, rm) for rm in model_choices])) + + if additional_query_string and additional_query_string != '*': + narrow_queries.add(additional_query_string) + + narrow_searcher = None + + if narrow_queries is not None: + # Potentially expensive? I don't see another way to do it in + # Whoosh... + narrow_searcher = self.index.searcher() + + for nq in narrow_queries: + recent_narrowed_results = narrow_searcher.search( + self.parser.parse(force_str(nq)), limit=None) + + if len(recent_narrowed_results) <= 0: + return { + 'results': [], + 'hits': 0, + } + + if narrowed_results: + narrowed_results.filter(recent_narrowed_results) + else: + narrowed_results = recent_narrowed_results + + page_num, page_length = self.calculate_page(start_offset, end_offset) + + self.index = self.index.refresh() + raw_results = EmptyResults() + + if self.index.doc_count(): + query = "%s:%s" % (ID, get_identifier(model_instance)) + searcher = self.index.searcher() + parsed_query = self.parser.parse(query) + results = searcher.search(parsed_query) + + if len(results): + raw_results = results[0].more_like_this( + field_name, top=end_offset) + + # Handle the case where the results have been narrowed. + if narrowed_results is not None and hasattr(raw_results, 'filter'): + raw_results.filter(narrowed_results) + + try: + raw_page = ResultsPage(raw_results, page_num, page_length) + except ValueError: + if not self.silently_fail: + raise + + return { + 'results': [], + 'hits': 0, + 'spelling_suggestion': None, + } + + # Because as of Whoosh 2.5.1, it will return the wrong page of + # results if you request something too high. :( + if raw_page.pagenum < page_num: + return { + 'results': [], + 'hits': 0, + 'spelling_suggestion': None, + } + + results = self._process_results(raw_page, result_class=result_class) + searcher.close() + + if hasattr(narrow_searcher, 'close'): + narrow_searcher.close() + + return results + + def _process_results( + self, + raw_page, + highlight=False, + query_string='', + spelling_query=None, + result_class=None): + from haystack import connections + results = [] + + # It's important to grab the hits first before slicing. Otherwise, this + # can cause pagination failures. + hits = len(raw_page) + + if result_class is None: + result_class = SearchResult + + facets = {} + spelling_suggestion = None + unified_index = connections[self.connection_alias].get_unified_index() + indexed_models = unified_index.get_indexed_models() + + for doc_offset, raw_result in enumerate(raw_page): + score = raw_page.score(doc_offset) or 0 + app_label, model_name = raw_result[DJANGO_CT].split('.') + additional_fields = {} + model = haystack_get_model(app_label, model_name) + + if model and model in indexed_models: + for key, value in raw_result.items(): + index = unified_index.get_index(model) + string_key = str(key) + + if string_key in index.fields and hasattr( + index.fields[string_key], 'convert'): + # Special-cased due to the nature of KEYWORD fields. + if index.fields[string_key].is_multivalued: + if value is None or len(value) == 0: + additional_fields[string_key] = [] + else: + additional_fields[string_key] = value.split( + ',') + else: + additional_fields[string_key] = index.fields[string_key].convert( + value) + else: + additional_fields[string_key] = self._to_python(value) + + del (additional_fields[DJANGO_CT]) + del (additional_fields[DJANGO_ID]) + + if highlight: + sa = StemmingAnalyzer() + formatter = WhooshHtmlFormatter('em') + terms = [token.text for token in sa(query_string)] + + whoosh_result = whoosh_highlight( + additional_fields.get(self.content_field_name), + terms, + sa, + ContextFragmenter(), + formatter + ) + additional_fields['highlighted'] = { + self.content_field_name: [whoosh_result], + } + + result = result_class( + app_label, + model_name, + raw_result[DJANGO_ID], + score, + **additional_fields) + results.append(result) + else: + hits -= 1 + + if self.include_spelling: + if spelling_query: + spelling_suggestion = self.create_spelling_suggestion( + spelling_query) + else: + spelling_suggestion = self.create_spelling_suggestion( + query_string) + + return { + 'results': results, + 'hits': hits, + 'facets': facets, + 'spelling_suggestion': spelling_suggestion, + } + + def create_spelling_suggestion(self, query_string): + spelling_suggestion = None + reader = self.index.reader() + corrector = reader.corrector(self.content_field_name) + cleaned_query = force_str(query_string) + + if not query_string: + return spelling_suggestion + + # Clean the string. + for rev_word in self.RESERVED_WORDS: + cleaned_query = cleaned_query.replace(rev_word, '') + + for rev_char in self.RESERVED_CHARACTERS: + cleaned_query = cleaned_query.replace(rev_char, '') + + # Break it down. + query_words = cleaned_query.split() + suggested_words = [] + + for word in query_words: + suggestions = corrector.suggest(word, limit=1) + + if len(suggestions) > 0: + suggested_words.append(suggestions[0]) + + spelling_suggestion = ' '.join(suggested_words) + return spelling_suggestion + + def _from_python(self, value): + """ + Converts Python values to a string for Whoosh. + + Code courtesy of pysolr. + """ + if hasattr(value, 'strftime'): + if not hasattr(value, 'hour'): + value = datetime(value.year, value.month, value.day, 0, 0, 0) + elif isinstance(value, bool): + if value: + value = 'true' + else: + value = 'false' + elif isinstance(value, (list, tuple)): + value = u','.join([force_str(v) for v in value]) + elif isinstance(value, (six.integer_types, float)): + # Leave it alone. + pass + else: + value = force_str(value) + return value + + def _to_python(self, value): + """ + Converts values from Whoosh to native Python values. + + A port of the same method in pysolr, as they deal with data the same way. + """ + if value == 'true': + return True + elif value == 'false': + return False + + if value and isinstance(value, six.string_types): + possible_datetime = DATETIME_REGEX.search(value) + + if possible_datetime: + date_values = possible_datetime.groupdict() + + for dk, dv in date_values.items(): + date_values[dk] = int(dv) + + return datetime( + date_values['year'], + date_values['month'], + date_values['day'], + date_values['hour'], + date_values['minute'], + date_values['second']) + + try: + # Attempt to use json to load the values. + converted_value = json.loads(value) + + # Try to handle most built-in types. + if isinstance( + converted_value, + (list, + tuple, + set, + dict, + six.integer_types, + float, + complex)): + return converted_value + except BaseException: + # If it fails (SyntaxError or its ilk) or we don't trust it, + # continue on. + pass + + return value + + +class WhooshSearchQuery(BaseSearchQuery): + def _convert_datetime(self, date): + if hasattr(date, 'hour'): + return force_str(date.strftime('%Y%m%d%H%M%S')) + else: + return force_str(date.strftime('%Y%m%d000000')) + + def clean(self, query_fragment): + """ + Provides a mechanism for sanitizing user input before presenting the + value to the backend. + + Whoosh 1.X differs here in that you can no longer use a backslash + to escape reserved characters. Instead, the whole word should be + quoted. + """ + words = query_fragment.split() + cleaned_words = [] + + for word in words: + if word in self.backend.RESERVED_WORDS: + word = word.replace(word, word.lower()) + + for char in self.backend.RESERVED_CHARACTERS: + if char in word: + word = "'%s'" % word + break + + cleaned_words.append(word) + + return ' '.join(cleaned_words) + + def build_query_fragment(self, field, filter_type, value): + from haystack import connections + query_frag = '' + is_datetime = False + + if not hasattr(value, 'input_type_name'): + # Handle when we've got a ``ValuesListQuerySet``... + if hasattr(value, 'values_list'): + value = list(value) + + if hasattr(value, 'strftime'): + is_datetime = True + + if isinstance(value, six.string_types) and value != ' ': + # It's not an ``InputType``. Assume ``Clean``. + value = Clean(value) + else: + value = PythonData(value) + + # Prepare the query using the InputType. + prepared_value = value.prepare(self) + + if not isinstance(prepared_value, (set, list, tuple)): + # Then convert whatever we get back to what pysolr wants if needed. + prepared_value = self.backend._from_python(prepared_value) + + # 'content' is a special reserved word, much like 'pk' in + # Django's ORM layer. It indicates 'no special field'. + if field == 'content': + index_fieldname = '' + else: + index_fieldname = u'%s:' % connections[self._using].get_unified_index( + ).get_index_fieldname(field) + + filter_types = { + 'content': '%s', + 'contains': '*%s*', + 'endswith': "*%s", + 'startswith': "%s*", + 'exact': '%s', + 'gt': "{%s to}", + 'gte': "[%s to]", + 'lt': "{to %s}", + 'lte': "[to %s]", + 'fuzzy': u'%s~', + } + + if value.post_process is False: + query_frag = prepared_value + else: + if filter_type in [ + 'content', + 'contains', + 'startswith', + 'endswith', + 'fuzzy']: + if value.input_type_name == 'exact': + query_frag = prepared_value + else: + # Iterate over terms & incorportate the converted form of + # each into the query. + terms = [] + + if isinstance(prepared_value, six.string_types): + possible_values = prepared_value.split(' ') + else: + if is_datetime is True: + prepared_value = self._convert_datetime( + prepared_value) + + possible_values = [prepared_value] + + for possible_value in possible_values: + terms.append( + filter_types[filter_type] % + self.backend._from_python(possible_value)) + + if len(terms) == 1: + query_frag = terms[0] + else: + query_frag = u"(%s)" % " AND ".join(terms) + elif filter_type == 'in': + in_options = [] + + for possible_value in prepared_value: + is_datetime = False + + if hasattr(possible_value, 'strftime'): + is_datetime = True + + pv = self.backend._from_python(possible_value) + + if is_datetime is True: + pv = self._convert_datetime(pv) + + if isinstance(pv, six.string_types) and not is_datetime: + in_options.append('"%s"' % pv) + else: + in_options.append('%s' % pv) + + query_frag = "(%s)" % " OR ".join(in_options) + elif filter_type == 'range': + start = self.backend._from_python(prepared_value[0]) + end = self.backend._from_python(prepared_value[1]) + + if hasattr(prepared_value[0], 'strftime'): + start = self._convert_datetime(start) + + if hasattr(prepared_value[1], 'strftime'): + end = self._convert_datetime(end) + + query_frag = u"[%s to %s]" % (start, end) + elif filter_type == 'exact': + if value.input_type_name == 'exact': + query_frag = prepared_value + else: + prepared_value = Exact(prepared_value).prepare(self) + query_frag = filter_types[filter_type] % prepared_value + else: + if is_datetime is True: + prepared_value = self._convert_datetime(prepared_value) + + query_frag = filter_types[filter_type] % prepared_value + + if len(query_frag) and not isinstance(value, Raw): + if not query_frag.startswith('(') and not query_frag.endswith(')'): + query_frag = "(%s)" % query_frag + + return u"%s%s" % (index_fieldname, query_frag) + + # if not filter_type in ('in', 'range'): + # # 'in' is a bit of a special case, as we don't want to + # # convert a valid list/tuple to string. Defer handling it + # # until later... + # value = self.backend._from_python(value) + + +class WhooshEngine(BaseEngine): + backend = WhooshSearchBackend + query = WhooshSearchQuery diff --git a/djangoblog/wsgi.py b/djangoblog/wsgi.py new file mode 100644 index 0000000..2295efd --- /dev/null +++ b/djangoblog/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for djangoblog project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/1.10/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "djangoblog.settings") + +application = get_wsgi_application() diff --git a/docs/README-en.md b/docs/README-en.md new file mode 100644 index 0000000..37ea069 --- /dev/null +++ b/docs/README-en.md @@ -0,0 +1,158 @@ +# DjangoBlog + +

+ Django CI + CodeQL + codecov + license +

+ +

+ A powerful, elegant, and modern blog system. +
+ English简体中文 +

+ +--- + +DjangoBlog is a high-performance blog platform built with Python 3.10 and Django 4.0. It not only provides all the core functionalities of a traditional blog but also features a flexible plugin system, allowing you to easily extend and customize your website. Whether you are a personal blogger, a tech enthusiast, or a content creator, DjangoBlog aims to provide a stable, efficient, and easy-to-maintain environment for writing and publishing. + +## ✨ Features + +- **Powerful Content Management**: Full support for managing articles, standalone pages, categories, and tags. Comes with a powerful built-in Markdown editor with syntax highlighting. +- **Full-Text Search**: Integrated search engine for fast and accurate content searching. +- **Interactive Comment System**: Supports replies, email notifications, and Markdown formatting in comments. +- **Flexible Sidebar**: Customizable modules for displaying recent articles, most viewed posts, tag cloud, and more. +- **Social Login**: Built-in OAuth support, with integrations for Google, GitHub, Facebook, Weibo, QQ, and other major platforms. +- **High-Performance Caching**: Native support for Redis caching with an automatic refresh mechanism to ensure high-speed website responses. +- **SEO Friendly**: Basic SEO features are included, with automatic notifications to Google and Baidu upon new content publication. +- **Extensible Plugin System**: Extend blog functionalities by creating standalone plugins, ensuring decoupled and maintainable code. We have already implemented features like view counting and SEO optimization through plugins! +- **Integrated Image Hosting**: A simple, built-in image hosting feature for easy uploads and management. +- **Automated Frontend**: Integrated with `django-compressor` to automatically compress and optimize CSS and JavaScript files. +- **Robust Operations**: Built-in email notifications for website exceptions and management capabilities through a WeChat Official Account. + +## 🛠️ Tech Stack + +- **Backend**: Python 3.10, Django 4.0 +- **Database**: MySQL, SQLite (configurable) +- **Cache**: Redis +- **Frontend**: HTML5, CSS3, JavaScript +- **Search**: Whoosh, Elasticsearch (configurable) +- **Editor**: Markdown (mdeditor) + +## 🚀 Getting Started + +### 1. Prerequisites + +Ensure you have Python 3.10+ and MySQL/MariaDB installed on your system. + +### 2. Clone & Installation + +```bash +# Clone the project to your local machine +git clone https://github.com/liangliangyy/DjangoBlog.git +cd DjangoBlog + +# Install dependencies +pip install -r requirements.txt +``` + +### 3. Project Configuration + +- **Database**: + Open `djangoblog/settings.py`, locate the `DATABASES` section, and update it with your MySQL connection details. + + ```python + DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': 'djangoblog', + 'USER': 'root', + 'PASSWORD': 'your_password', + 'HOST': '127.0.0.1', + 'PORT': 3306, + } + } + ``` + Create the database in MySQL: + ```sql + CREATE DATABASE `djangoblog` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + ``` + +- **More Configurations**: + For advanced settings such as email, OAuth, caching, and more, please refer to our [Detailed Configuration Guide](/docs/config-en.md). + +### 4. Database Initialization + +```bash +python manage.py makemigrations +python manage.py migrate + +# Create a superuser account +python manage.py createsuperuser +``` + +### 5. Running the Project + +```bash +# (Optional) Generate some test data +python manage.py create_testdata + +# (Optional) Collect and compress static files +python manage.py collectstatic --noinput +python manage.py compress --force + +# Start the development server +python manage.py runserver +``` + +Now, open your browser and navigate to `http://127.0.0.1:8000/`. You should see the DjangoBlog homepage! + +## Deployment + +- **Traditional Deployment**: A detailed guide for server deployment is available here: [Deployment Tutorial](https://www.lylinux.net/article/2019/8/5/58.html) (in Chinese). +- **Docker Deployment**: This project fully supports Docker. If you are familiar with containerization, please refer to the [Docker Deployment Guide](/docs/docker-en.md) for a quick start. +- **Kubernetes Deployment**: We also provide a complete [Kubernetes Deployment Guide](/docs/k8s-en.md) to help you go cloud-native easily. + +## 🧩 Plugin System + +The plugin system is a core feature of DjangoBlog. It allows you to add new functionalities to your blog without modifying the core codebase by writing standalone plugins. + +- **How it Works**: Plugins operate by registering callback functions to predefined "hooks". For instance, when an article is rendered, the `after_article_body_get` hook is triggered, and all functions registered to this hook are executed. +- **Existing Plugins**: Features like `view_count` and `seo_optimizer` are implemented through this plugin system. +- **Develop Your Own Plugin**: Simply create a new folder under the `plugins` directory and write your `plugin.py`. We welcome you to explore and contribute your creative ideas to the DjangoBlog community! + +## 🤝 Contributing + +We warmly welcome contributions of any kind! If you have great ideas or have found a bug, please feel free to open an issue or submit a pull request. + +## 📄 License + +This project is open-sourced under the [MIT License](LICENSE). + +--- + +## ❤️ Support & Sponsorship + +If you find this project helpful and wish to support its continued maintenance and development, please consider buying me a coffee! Your support is my greatest motivation. + +

+ Alipay Sponsorship + WeChat Sponsorship +

+

+ (Left) Alipay / (Right) WeChat +

+ +## 🙏 Acknowledgements + +A special thanks to **JetBrains** for providing a free open-source license for this project. + +

+ + JetBrains Logo + +

+ +--- +> If this project has helped you, please leave your website URL [here](https://github.com/liangliangyy/DjangoBlog/issues/214) to let more people see it. Your feedback is the driving force for my continued updates and maintenance. diff --git a/docs/config-en.md b/docs/config-en.md new file mode 100644 index 0000000..b877efb --- /dev/null +++ b/docs/config-en.md @@ -0,0 +1,64 @@ +# Introduction to main features settings + +## Cache: +Cache using `memcache` for default. If you don't have `memcache` environment, you can remove the `default` setting in `CACHES` and change `locmemcache` to `default`. +```python +CACHES = { + 'default': { + 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', + 'LOCATION': '127.0.0.1:11211', + 'KEY_PREFIX': 'django_test' if TESTING else 'djangoblog', + 'TIMEOUT': 60 * 60 * 10 + }, + 'locmemcache': { + 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', + 'TIMEOUT': 10800, + 'LOCATION': 'unique-snowflake', + } +} +``` + +## OAuth Login: +QQ, Weibo, Google, GitHub and Facebook are now supported for OAuth login. Fetch OAuth login permissions from the corresponding open platform, and save them with `appkey`, `appsecret` and callback address in **Backend->OAuth** configuration. + +### Callback address examples: +QQ: http://your-domain-name/oauth/authorize?type=qq +Weibo: http://your-domain-name/oauth/authorize?type=weibo +type is in the type field of `oauthmanager`. + +## owntracks: +owntracks is a location tracking application. It will send your locaiton to the server by timing.Simple support owntracks features. Just install owntracks app and set api address as `your-domain-name/owntracks/logtracks`. Visit `your-domain-name/owntracks/show_dates` and you will see the date with latitude and langitude, click it and see the motion track. The map is drawn by AMap. + +## Email feature: +Same as before, Configure your own error msg recvie email information with`ADMINS = [('liangliang', 'liangliangyy@gmail.com')]` in `settings.py`. And modify: +```python +EMAIL_HOST = 'smtp.zoho.com' +EMAIL_PORT = 587 +EMAIL_HOST_USER = os.environ.get('DJANGO_EMAIL_USER') +EMAIL_HOST_PASSWORD = os.environ.get('DJANGO_EMAIL_PASSWORD') +DEFAULT_FROM_EMAIL = EMAIL_HOST_USER +SERVER_EMAIL = os.environ.get('DJANGO_EMAIL_USER') +``` +with your email account information. + +## WeChat Official Account +Simple wechat official account features integrated. Set token as `your-domain-name/robot` in wechat backend. Default token is `lylinux`, you can change it to your own in `servermanager/robot.py`. Add a new command in `Backend->Servermanager->command`, in this way, you can manage the system through wechat official account. + +## Introduction to website configuration +You can add website configuration in **Backend->BLOG->WebSiteConfiguration**. Such as: keywords, description, Google Ad, website stats code, case number, etc. +OAuth user avatar path is saved in *StaticFileSavedAddress*. Please input absolute path, code directory for default. + +## Source code highlighting +If the code block in your article didn't show hightlight, please write the code blocks as following: + +![](https://resource.lylinux.net/image/codelang.png) + +That is, you should add the corresponding language name before the code block. + +## Update +If you get errors as following while executing database migrations: +```python +django.db.migrations.exceptions.MigrationSchemaMissing: Unable to create the django_migrations table ((1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(6) NOT NULL)' at line 1")) +``` +This problem may cause by the mysql version under 5.6, a new version( >= 5.6 ) mysql is needed. + diff --git a/docs/config.md b/docs/config.md new file mode 100644 index 0000000..24673a3 --- /dev/null +++ b/docs/config.md @@ -0,0 +1,58 @@ +# 主要功能配置介绍: + +## 缓存: +缓存默认使用`localmem`缓存,如果你有`redis`环境,可以设置`DJANGO_REDIS_URL`环境变量,则会自动使用该redis来作为缓存,或者你也可以直接修改如下代码来使用。 +https://github.com/liangliangyy/DjangoBlog/blob/ffcb2c3711de805f2067dd3c1c57449cd24d84ee/djangoblog/settings.py#L185-L199 + + +## oauth登录: + +现在已经支持QQ,微博,Google,GitHub,Facebook登录,需要在其对应的开放平台申请oauth登录权限,然后在 +**后台->Oauth** 配置中新增配置,填写对应的`appkey`和`appsecret`以及回调地址。 +### 回调地址示例: +qq:http://你的域名/oauth/authorize?type=qq +微博:http://你的域名/oauth/authorize?type=weibo +type对应在`oauthmanager`中的type字段。 + +## owntracks: +owntracks是一个位置追踪软件,可以定时的将你的坐标提交到你的服务器上,现在简单的支持owntracks功能,需要安装owntracks的app,然后将api地址设置为: +`你的域名/owntracks/logtracks`就可以了。然后访问`你的域名/owntracks/show_dates`就可以看到有经纬度记录的日期,点击之后就可以看到运动轨迹了。地图是使用高德地图绘制。 + +## 邮件功能: +同样,将`settings.py`中的`ADMINS = [('liangliang', 'liangliangyy@gmail.com')]`配置为你自己的错误接收邮箱,另外修改: +```python +EMAIL_HOST = 'smtp.zoho.com' +EMAIL_PORT = 587 +EMAIL_HOST_USER = os.environ.get('DJANGO_EMAIL_USER') +EMAIL_HOST_PASSWORD = os.environ.get('DJANGO_EMAIL_PASSWORD') +DEFAULT_FROM_EMAIL = EMAIL_HOST_USER +SERVER_EMAIL = os.environ.get('DJANGO_EMAIL_USER') +``` +为你自己的邮箱配置。 + +## 微信公众号 +集成了简单的微信公众号功能,在微信后台将token地址设置为:`你的域名/robot` 即可,默认token为`lylinux`,当然你可以修改为你自己的,在`servermanager/robot.py`中。 +然后在**后台->Servermanager->命令**中新增命令,这样就可以使用微信公众号来管理了。 +## 网站配置介绍 +在**后台->BLOG->网站配置**中,可以新增网站配置,比如关键字,描述等,以及谷歌广告,网站统计代码及备案号等等。 +其中的*静态文件保存地址*是保存oauth用户登录的头像路径,填写绝对路径,默认是代码目录。 +## 代码高亮 +如果你发现你文章的代码没有高亮,请这样书写代码块: + +![](https://resource.lylinux.net/image/codelang.png) + + +也就是说,需要在代码块开始位置加入这段代码对应的语言。 + +## update +如果你发现执行数据库迁移的时候出现如下报错: +```python +django.db.migrations.exceptions.MigrationSchemaMissing: Unable to create the django_migrations table ((1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(6) NOT NULL)' at line 1")) +``` +可能是因为你的mysql版本低于5.6,需要升级mysql版本>=5.6即可。 + + +django 4.0登录可能会报错CSRF,需要配置下`settings.py`中的`CSRF_TRUSTED_ORIGINS` + +https://github.com/liangliangyy/DjangoBlog/blob/master/djangoblog/settings.py#L39 + diff --git a/docs/docker-en.md b/docs/docker-en.md new file mode 100644 index 0000000..8d5d59e --- /dev/null +++ b/docs/docker-en.md @@ -0,0 +1,114 @@ +# Deploying DjangoBlog with Docker + +![Docker Pulls](https://img.shields.io/docker/pulls/liangliangyy/djangoblog) +![Docker Image Version (latest by date)](https://img.shields.io/docker/v/liangliangyy/djangoblog?sort=date) +![Docker Image Size (latest by date)](https://img.shields.io/docker/image-size/liangliangyy/djangoblog) + +This project fully supports containerized deployment using Docker, providing you with a fast, consistent, and isolated runtime environment. We recommend using `docker-compose` to launch the entire blog service stack with a single command. + +## 1. Prerequisites + +Before you begin, please ensure you have the following software installed on your system: +- [Docker Engine](https://docs.docker.com/engine/install/) +- [Docker Compose](https://docs.docker.com/compose/install/) (Included with Docker Desktop for Mac and Windows) + +## 2. Recommended Method: Using `docker-compose` (One-Click Deployment) + +This is the simplest and most recommended way to deploy. It automatically creates and manages the Django application, a MySQL database, and an optional Elasticsearch service for you. + +### Step 1: Start the Basic Services + +From the project's root directory, run the following command: + +```bash +# Build and start the containers in detached mode (includes Django app and MySQL) +docker-compose up -d --build +``` + +`docker-compose` will read the `docker-compose.yml` file, pull the necessary images, build the project image, and start all services. + +- **Access Your Blog**: Once the services are up, you can access the blog by navigating to `http://127.0.0.1` in your browser. +- **Data Persistence**: MySQL data files will be stored in the `data/mysql` directory within the project root, ensuring that your data persists across container restarts. + +### Step 2: (Optional) Enable Elasticsearch for Full-Text Search + +If you want to use Elasticsearch for more powerful full-text search capabilities, you can include the `docker-compose.es.yml` configuration file: + +```bash +# Build and start all services in detached mode (Django, MySQL, Elasticsearch) +docker-compose -f docker-compose.yml -f deploy/docker-compose/docker-compose.es.yml up -d --build +``` +- **Data Persistence**: Elasticsearch data will be stored in the `data/elasticsearch` directory. + +### Step 3: First-Time Initialization + +After the containers start for the first time, you'll need to execute some initialization commands inside the application container. + +```bash +# Get a shell inside the djangoblog application container (named 'web') +docker-compose exec web bash + +# Inside the container, run the following commands: +# Create a superuser account (follow the prompts to set username, email, and password) +python manage.py createsuperuser + +# (Optional) Create some test data +python manage.py create_testdata + +# (Optional, if ES is enabled) Create the search index +python manage.py rebuild_index + +# Exit the container +exit +``` + +## 3. Alternative Method: Using the Standalone Docker Image + +If you already have an external MySQL database running, you can run the DjangoBlog application image by itself. + +```bash +# Pull the latest image from Docker Hub +docker pull liangliangyy/djangoblog:latest + +# Run the container and connect it to your external database +docker run -d \ + -p 8000:8000 \ + -e DJANGO_SECRET_KEY='your-strong-secret-key' \ + -e DJANGO_MYSQL_HOST='your-mysql-host' \ + -e DJANGO_MYSQL_USER='your-mysql-user' \ + -e DJANGO_MYSQL_PASSWORD='your-mysql-password' \ + -e DJANGO_MYSQL_DATABASE='djangoblog' \ + --name djangoblog \ + liangliangyy/djangoblog:latest +``` + +- **Access Your Blog**: After startup, visit `http://127.0.0.1:8000`. +- **Create Superuser**: `docker exec -it djangoblog python manage.py createsuperuser` + +## 4. Configuration (Environment Variables) + +Most of the project's configuration is managed through environment variables. You can modify them in the `docker-compose.yml` file or pass them using the `-e` flag with the `docker run` command. + +| Environment Variable | Default/Example Value | Notes | +|---------------------------|--------------------------------------------------------------------------|---------------------------------------------------------------------| +| `DJANGO_SECRET_KEY` | `your-strong-secret-key` | **Must be changed to a random, complex string!** | +| `DJANGO_DEBUG` | `False` | Toggles Django's debug mode. | +| `DJANGO_MYSQL_HOST` | `mysql` | Database hostname. | +| `DJANGO_MYSQL_PORT` | `3306` | Database port. | +| `DJANGO_MYSQL_DATABASE` | `djangoblog` | Database name. | +| `DJANGO_MYSQL_USER` | `root` | Database username. | +| `DJANGO_MYSQL_PASSWORD` | `djangoblog_123` | Database password. | +| `DJANGO_REDIS_URL` | `redis:6379/0` | Redis connection URL (for caching). | +| `DJANGO_ELASTICSEARCH_HOST`| `elasticsearch:9200` | Elasticsearch host address. | +| `DJANGO_EMAIL_HOST` | `smtp.example.org` | Email server address. | +| `DJANGO_EMAIL_PORT` | `465` | Email server port. | +| `DJANGO_EMAIL_USER` | `user@example.org` | Email account username. | +| `DJANGO_EMAIL_PASSWORD` | `your-email-password` | Email account password. | +| `DJANGO_EMAIL_USE_SSL` | `True` | Whether to use SSL. | +| `DJANGO_EMAIL_USE_TLS` | `False` | Whether to use TLS. | +| `DJANGO_ADMIN_EMAIL` | `admin@example.org` | Admin email for receiving error reports. | +| `DJANGO_BAIDU_NOTIFY_URL` | `http://data.zz.baidu.com/...` | Push API from [Baidu Webmaster Tools](https://ziyuan.baidu.com/linksubmit/index). | + +--- + +After deployment, please review and adjust these environment variables according to your needs, especially `DJANGO_SECRET_KEY` and the database and email settings. \ No newline at end of file diff --git a/docs/docker.md b/docs/docker.md new file mode 100644 index 0000000..e7c255a --- /dev/null +++ b/docs/docker.md @@ -0,0 +1,114 @@ +# 使用 Docker 部署 DjangoBlog + +![Docker Pulls](https://img.shields.io/docker/pulls/liangliangyy/djangoblog) +![Docker Image Version (latest by date)](https://img.shields.io/docker/v/liangliangyy/djangoblog?sort=date) +![Docker Image Size (latest by date)](https://img.shields.io/docker/image-size/liangliangyy/djangoblog) + +本项目全面支持使用 Docker 进行容器化部署,为您提供了快速、一致且隔离的运行环境。我们推荐使用 `docker-compose` 来一键启动整个博客服务栈。 + +## 1. 环境准备 + +在开始之前,请确保您的系统中已经安装了以下软件: +- [Docker Engine](https://docs.docker.com/engine/install/) +- [Docker Compose](https://docs.docker.com/compose/install/) (对于 Docker Desktop 用户,它已内置) + +## 2. 推荐方式:使用 `docker-compose` (一键部署) + +这是最简单、最推荐的部署方式。它会自动为您创建并管理 Django 应用、MySQL 数据库,以及可选的 Elasticsearch 服务。 + +### 步骤 1: 启动基础服务 + +在项目根目录下,执行以下命令: + +```bash +# 构建并以后台模式启动容器 (包含 Django 应用和 MySQL) +docker-compose up -d --build +``` + +`docker-compose` 会读取 `docker-compose.yml` 文件,自动拉取所需镜像、构建项目镜像,并启动所有服务。 + +- **访问您的博客**: 服务启动后,在浏览器中访问 `http://127.0.0.1` 即可看到博客首页。 +- **数据持久化**: MySQL 的数据文件将存储在项目根目录下的 `data/mysql` 文件夹中,确保数据在容器重启后不丢失。 + +### 步骤 2: (可选) 启用 Elasticsearch 全文搜索 + +如果您希望使用 Elasticsearch 提供更强大的全文搜索功能,可以额外加载 `docker-compose.es.yml` 配置文件: + +```bash +# 构建并以后台模式启动所有服务 (Django, MySQL, Elasticsearch) +docker-compose -f docker-compose.yml -f deploy/docker-compose/docker-compose.es.yml up -d --build +``` +- **数据持久化**: Elasticsearch 的数据将存储在 `data/elasticsearch` 文件夹中。 + +### 步骤 3: 首次运行的初始化操作 + +当容器首次启动后,您需要进入容器来执行一些初始化命令。 + +```bash +# 进入 djangoblog 应用容器 +docker-compose exec web bash + +# 在容器内执行以下命令: +# 创建超级管理员账户 (请按照提示设置用户名、邮箱和密码) +python manage.py createsuperuser + +# (可选) 创建一些测试数据 +python manage.py create_testdata + +# (可选,如果启用了 ES) 创建索引 +python manage.py rebuild_index + +# 退出容器 +exit +``` + +## 3. 备选方式:使用独立的 Docker 镜像 + +如果您已经拥有一个正在运行的外部 MySQL 数据库,您也可以只运行 DjangoBlog 的应用镜像。 + +```bash +# 从 Docker Hub 拉取最新镜像 +docker pull liangliangyy/djangoblog:latest + +# 运行容器,并链接到您的外部数据库 +docker run -d \ + -p 8000:8000 \ + -e DJANGO_SECRET_KEY='your-strong-secret-key' \ + -e DJANGO_MYSQL_HOST='your-mysql-host' \ + -e DJANGO_MYSQL_USER='your-mysql-user' \ + -e DJANGO_MYSQL_PASSWORD='your-mysql-password' \ + -e DJANGO_MYSQL_DATABASE='djangoblog' \ + --name djangoblog \ + liangliangyy/djangoblog:latest +``` + +- **访问您的博客**: 启动完成后,访问 `http://127.0.0.1:8000`。 +- **创建管理员**: `docker exec -it djangoblog python manage.py createsuperuser` + +## 4. 配置说明 (环境变量) + +本项目的大部分配置都通过环境变量来管理。您可以在 `docker-compose.yml` 文件中修改它们,或者在使用 `docker run` 命令时通过 `-e` 参数传入。 + +| 环境变量名称 | 默认值/示例 | 备注 | +|-------------------------|--------------------------------------------------------------------------|---------------------------------------------------------------------| +| `DJANGO_SECRET_KEY` | `your-strong-secret-key` | **请务必修改为一个随机且复杂的字符串!** | +| `DJANGO_DEBUG` | `False` | 是否开启 Django 的调试模式 | +| `DJANGO_MYSQL_HOST` | `mysql` | 数据库主机名 | +| `DJANGO_MYSQL_PORT` | `3306` | 数据库端口 | +| `DJANGO_MYSQL_DATABASE` | `djangoblog` | 数据库名称 | +| `DJANGO_MYSQL_USER` | `root` | 数据库用户名 | +| `DJANGO_MYSQL_PASSWORD` | `djangoblog_123` | 数据库密码 | +| `DJANGO_REDIS_URL` | `redis:6379/0` | Redis 连接地址 (用于缓存) | +| `DJANGO_ELASTICSEARCH_HOST` | `elasticsearch:9200` | Elasticsearch 主机地址 | +| `DJANGO_EMAIL_HOST` | `smtp.example.org` | 邮件服务器地址 | +| `DJANGO_EMAIL_PORT` | `465` | 邮件服务器端口 | +| `DJANGO_EMAIL_USER` | `user@example.org` | 邮件账户 | +| `DJANGO_EMAIL_PASSWORD` | `your-email-password` | 邮件密码 | +| `DJANGO_EMAIL_USE_SSL` | `True` | 是否使用 SSL | +| `DJANGO_EMAIL_USE_TLS` | `False` | 是否使用 TLS | +| `DJANGO_ADMIN_EMAIL` | `admin@example.org` | 接收异常报告的管理员邮箱 | +| `DJANGO_BAIDU_NOTIFY_URL` | `http://data.zz.baidu.com/...` | [百度站长平台](https://ziyuan.baidu.com/linksubmit/index) 的推送接口 | + +--- + +部署完成后,请务必检查并根据您的实际需求调整这些环境变量,特别是 `DJANGO_SECRET_KEY` 和数据库、邮件相关的配置。 diff --git a/docs/es.md b/docs/es.md new file mode 100644 index 0000000..97226c5 --- /dev/null +++ b/docs/es.md @@ -0,0 +1,28 @@ +# 集成Elasticsearch +如果你已经有了`Elasticsearch`环境,那么可以将搜索从`Whoosh`换成`Elasticsearch`,集成方式也很简单, +首先需要注意如下几点: +1. 你的`Elasticsearch`支持`ik`中文分词 +2. 你的`Elasticsearch`版本>=7.3.0 + +接下来在`settings.py`做如下改动即可: +- 增加es链接,如下所示: +```python +ELASTICSEARCH_DSL = { + 'default': { + 'hosts': '127.0.0.1:9200' + }, +} +``` +- 修改`HAYSTACK`配置: +```python +HAYSTACK_CONNECTIONS = { + 'default': { + 'ENGINE': 'djangoblog.elasticsearch_backend.ElasticSearchEngine', + }, +} +``` +然后终端执行: +```shell script +./manage.py build_index +``` +这将会在你的es中创建两个索引,分别是`blog`和`performance`,其中`blog`索引就是搜索所使用的,而`performance`会记录每个请求的响应时间,以供将来优化使用。 \ No newline at end of file diff --git a/docs/imgs/alipay.jpg b/docs/imgs/alipay.jpg new file mode 100644 index 0000000000000000000000000000000000000000..424d70a2ffbb629b481e0c27d72d6076727e8041 GIT binary patch literal 17961 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⁡O0bI!3Bi@jSTgKn>Bg&Q53II7XEA`NhoOY$25L(eK?<1>~>hujoRs}yUHVX zQTt}~MN1Zw0!xe7-aUbnm3fxd*KjwLLobx-SSZdGT`vUtB-=hS^~#Rs9K<#Wao{Zp z{kmB)_tVwwglj-W2qla4$Dx zz53|611jp`Ro8}#TnY+1OdA}SN;lGY+!=)=QY;q0b}yA~i0O^|s1#r34{5DET&Qh` z+yAF+h#H($?p6{{X zz@F@jlhUjuyW%|!{Q!~$q>$)y1Hsl$FMYS;#r=c7U7SN-8Uv-lv<@mZOXKOlXLy4C z3v?;Yh1KbtsO!ynC%cyr-`4MR8{Y~e28GXK7yRZ9{3d5(xoP=XYdX*Uy?#pU$a5>& z`JUOV_ zRl}`OH8`y;U%XD+MFBD!HxL@B`JSH_G!;0V9-A+_4Hhf%=wJ%txE{qNaHkfkLsS+h zfe@JrYreKrFKhU2`1kD)K_#LCd!v$sI$is2ee^7Am=@kq2Z-`cU(l{<8*ON_J?@@& zOR+4E3%sN-vIK-%81R}RdPK$bCrBoGF zRu$>N^0s*R^!6R919|j@|cY|A}(o`$`Onha=;(7(EQNg;0 z^sK+j)DQ>i-wCKpkXH^lH{QNw|FWJ%bUle^xtPfLdv#(gNpA7lv59GyIOXp*E+vz_!y|AkM=lB7mYXSWGfxr6#WlV5UW{v7tVn1!e zwg=v}kG!o+0qXfY-FyUozk}%&PS$ZRL^NoDuz%nVw(p)FVMPG6Ph*mgs4z0~C)P`9 zWsg_X!-)T2FkH=VqaRBu8Zkq=AX6oLSWpg(yQ^NIftdmxjx literal 0 HcmV?d00001 diff --git a/docs/imgs/pycharm_logo.png b/docs/imgs/pycharm_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..7f2a4b0ea66469bd218774de8cb3027a9c18b84d GIT binary patch literal 132045 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 z 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

*$hI3G#u%WdV|9<`IE_VBVx2~ei~?p& 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


AewDOjh!MMu(vjQJBsiX3ZCmAui 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 literal 0 HcmV?d00001 diff --git a/docs/k8s-en.md b/docs/k8s-en.md new file mode 100644 index 0000000..20e9527 --- /dev/null +++ b/docs/k8s-en.md @@ -0,0 +1,141 @@ +# Deploying DjangoBlog with Kubernetes + +This document guides you through deploying the DjangoBlog application on a Kubernetes (K8s) cluster. We provide a complete set of `.yaml` configuration files in the `deploy/k8s` directory to deploy a full service stack, including the DjangoBlog application, Nginx, MySQL, Redis, and Elasticsearch. + +## Architecture Overview + +This deployment utilizes a microservices-based, cloud-native architecture: + +- **Core Components**: Each core service (DjangoBlog, Nginx, MySQL, Redis, Elasticsearch) runs as a separate `Deployment`. +- **Configuration Management**: Nginx configurations and Django application environment variables are managed via `ConfigMap`. **Note: For sensitive information like passwords, using `Secret` is highly recommended.** +- **Service Discovery**: All services are exposed internally within the cluster as `ClusterIP` type `Service`, enabling communication via service names. +- **External Access**: An `Ingress` resource is used to route external HTTP traffic to the Nginx service, which acts as the single entry point for the entire blog application. +- **Data Persistence**: A `local-storage` solution based on node-local paths is used. This requires you to manually create storage directories on a specific K8s node and statically bind them using `PersistentVolume` (PV) and `PersistentVolumeClaim` (PVC). + +## 1. Prerequisites + +Before you begin, please ensure you have the following: + +- A running Kubernetes cluster. +- The `kubectl` command-line tool configured to connect to your cluster. +- An [Nginx Ingress Controller](https://kubernetes.github.io/ingress-nginx/deploy/) installed and configured in your cluster. +- Filesystem access to one of the nodes in your cluster (defaulted to `master` in the configs) to create local storage directories. + +## 2. Deployment Steps + +### Step 1: Create a Namespace + +We recommend deploying all DjangoBlog-related resources in a dedicated namespace for better management. + +```bash +# Create a namespace named 'djangoblog' +kubectl create namespace djangoblog +``` + +### Step 2: Configure Persistent Storage + +This setup uses Local Persistent Volumes. You need to create the data storage directories on a node within your cluster (the default is the `master` node in `pv.yaml`). + +```bash +# Log in to your master node +ssh user@master-node + +# Create the required storage directories +sudo mkdir -p /mnt/local-storage-db +sudo mkdir -p /mnt/local-storage-djangoblog +sudo mkdir -p /mnt/resource/ +sudo mkdir -p /mnt/local-storage-elasticsearch + +# Log out from the node +exit +``` +**Note**: If you wish to store data on a different node or use different paths, you must modify the `nodeAffinity` and `local.path` settings in the `deploy/k8s/pv.yaml` file. + +After creating the directories, apply the storage-related configurations: + +```bash +# Apply the StorageClass +kubectl apply -f deploy/k8s/storageclass.yaml + +# Apply the PersistentVolumes (PVs) +kubectl apply -f deploy/k8s/pv.yaml + +# Apply the PersistentVolumeClaims (PVCs) +kubectl apply -f deploy/k8s/pvc.yaml +``` + +### Step 3: Configure the Application + +Before deploying the application, you need to edit the `deploy/k8s/configmap.yaml` file to modify sensitive information and custom settings. + +**It is strongly recommended to change the following fields:** +- `DJANGO_SECRET_KEY`: Change to a random, complex string. +- `DJANGO_MYSQL_PASSWORD` and `MYSQL_ROOT_PASSWORD`: Change to your own secure database password. + +```bash +# Edit the ConfigMap file +vim deploy/k8s/configmap.yaml + +# Apply the configuration +kubectl apply -f deploy/k8s/configmap.yaml +``` + +### Step 4: Deploy the Application Stack + +Now, we can deploy all the core services. + +```bash +# Deploy the Deployments (DjangoBlog, MySQL, Redis, Nginx, ES) +kubectl apply -f deploy/k8s/deployment.yaml + +# Deploy the Services (to create internal endpoints for the Deployments) +kubectl apply -f deploy/k8s/service.yaml +``` + +The deployment may take some time. You can run the following command to check if all Pods are running successfully (STATUS should be `Running`): + +```bash +kubectl get pods -n djangoblog -w +``` + +### Step 5: Expose the Application Externally + +Finally, expose the Nginx service to external traffic by applying the `Ingress` rule. + +```bash +# Apply the Ingress rule +kubectl apply -f deploy/k8s/gateway.yaml +``` + +Once deployed, you can access your blog via the external IP address of your Ingress Controller. Use the following command to find the address: + +```bash +kubectl get ingress -n djangoblog +``` + +### Step 6: First-Time Initialization + +Similar to the Docker deployment, you need to get a shell into the DjangoBlog application Pod to perform database initialization and create a superuser on the first run. + +```bash +# First, get the name of a djangoblog pod +kubectl get pods -n djangoblog | grep djangoblog + +# Exec into one of the Pods (replace [pod-name] with the name from the previous step) +kubectl exec -it [pod-name] -n djangoblog -- bash + +# Inside the Pod, run the following commands: +# Create a superuser account (follow the prompts) +python manage.py createsuperuser + +# (Optional) Create some test data +python manage.py create_testdata + +# (Optional, if ES is enabled) Create the search index +python manage.py rebuild_index + +# Exit the Pod +exit +``` + +Congratulations! You have successfully deployed DjangoBlog on your Kubernetes cluster. \ No newline at end of file diff --git a/docs/k8s.md b/docs/k8s.md new file mode 100644 index 0000000..9da3c28 --- /dev/null +++ b/docs/k8s.md @@ -0,0 +1,141 @@ +# 使用 Kubernetes 部署 DjangoBlog + +本文档将指导您如何在 Kubernetes (K8s) 集群上部署 DjangoBlog 应用。我们提供了一套完整的 `.yaml` 配置文件,位于 `deploy/k8s` 目录下,用于部署一个包含 DjangoBlog 应用、Nginx、MySQL、Redis 和 Elasticsearch 的完整服务栈。 + +## 架构概览 + +本次部署采用的是微服务化的云原生架构: + +- **核心组件**: 每个核心服务 (DjangoBlog, Nginx, MySQL, Redis, Elasticsearch) 都将作为独立的 `Deployment` 运行。 +- **配置管理**: Nginx 的配置文件和 Django 应用的环境变量通过 `ConfigMap` 进行管理。**注意:敏感信息(如密码)建议使用 `Secret` 进行管理。** +- **服务发现**: 所有服务都通过 `ClusterIP` 类型的 `Service` 在集群内部暴露,并通过服务名相互通信。 +- **外部访问**: 使用 `Ingress` 资源将外部的 HTTP 流量路由到 Nginx 服务,作为整个博客应用的统一入口。 +- **数据持久化**: 采用基于节点本地路径的 `local-storage` 方案。这需要您在指定的 K8s 节点上手动创建存储目录,并通过 `PersistentVolume` (PV) 和 `PersistentVolumeClaim` (PVC) 进行静态绑定。 + +## 1. 环境准备 + +在开始之前,请确保您已具备以下环境: + +- 一个正在运行的 Kubernetes 集群。 +- `kubectl` 命令行工具已配置并能够连接到您的集群。 +- 集群中已安装并配置好 [Nginx Ingress Controller](https://kubernetes.github.io/ingress-nginx/deploy/)。 +- 对集群中的一个节点(默认为 `master`)拥有文件系统访问权限,用于创建本地存储目录。 + +## 2. 部署步骤 + +### 步骤 1: 创建命名空间 + +我们建议将 DjangoBlog 相关的所有资源都部署在一个独立的命名空间中,便于管理。 + +```bash +# 创建一个名为 djangoblog 的命名空间 +kubectl create namespace djangoblog +``` + +### 步骤 2: 配置持久化存储 + +此方案使用本地持久卷 (Local Persistent Volume)。您需要在集群的一个节点上(在 `pv.yaml` 文件中默认为 `master` 节点)创建用于数据存储的目录。 + +```bash +# 登录到您的 master 节点 +ssh user@master-node + +# 创建所需的存储目录 +sudo mkdir -p /mnt/local-storage-db +sudo mkdir -p /mnt/local-storage-djangoblog +sudo mkdir -p /mnt/resource/ +sudo mkdir -p /mnt/local-storage-elasticsearch + +# 退出节点 +exit +``` +**注意**: 如果您希望将数据存储在其他节点或使用不同的路径,请务必修改 `deploy/k8s/pv.yaml` 文件中 `nodeAffinity` 和 `local.path` 的配置。 + +创建目录后,应用存储相关的配置文件: + +```bash +# 应用 StorageClass +kubectl apply -f deploy/k8s/storageclass.yaml + +# 应用 PersistentVolume (PV) +kubectl apply -f deploy/k8s/pv.yaml + +# 应用 PersistentVolumeClaim (PVC) +kubectl apply -f deploy/k8s/pvc.yaml +``` + +### 步骤 3: 配置应用 + +在部署应用之前,您需要编辑 `deploy/k8s/configmap.yaml` 文件,修改其中的敏感信息和个性化配置。 + +**强烈建议修改以下字段:** +- `DJANGO_SECRET_KEY`: 修改为一个随机且复杂的字符串。 +- `DJANGO_MYSQL_PASSWORD` 和 `MYSQL_ROOT_PASSWORD`: 修改为您自己的数据库密码。 + +```bash +# 编辑 ConfigMap 文件 +vim deploy/k8s/configmap.yaml + +# 应用配置 +kubectl apply -f deploy/k8s/configmap.yaml +``` + +### 步骤 4: 部署应用服务栈 + +现在,我们可以部署所有的核心服务了。 + +```bash +# 部署 Deployments (DjangoBlog, MySQL, Redis, Nginx, ES) +kubectl apply -f deploy/k8s/deployment.yaml + +# 部署 Services (为 Deployments 创建内部访问端点) +kubectl apply -f deploy/k8s/service.yaml +``` + +部署需要一些时间,您可以运行以下命令检查所有 Pod 是否都已成功运行 (STATUS 为 `Running`): + +```bash +kubectl get pods -n djangoblog -w +``` + +### 步骤 5: 暴露应用到外部 + +最后,通过应用 `Ingress` 规则来将外部流量引导至我们的 Nginx 服务。 + +```bash +# 应用 Ingress 规则 +kubectl apply -f deploy/k8s/gateway.yaml +``` + +部署完成后,您可以通过 Ingress Controller 的外部 IP 地址来访问您的博客。执行以下命令获取地址: + +```bash +kubectl get ingress -n djangoblog +``` + +### 步骤 6: 首次运行的初始化操作 + +与 Docker 部署类似,首次运行时,您需要进入 DjangoBlog 应用的 Pod 来执行数据库初始化和创建管理员账户。 + +```bash +# 首先,获取 djangoblog pod 的名称 +kubectl get pods -n djangoblog | grep djangoblog + +# 进入其中一个 Pod (将 [pod-name] 替换为上一步获取到的名称) +kubectl exec -it [pod-name] -n djangoblog -- bash + +# 在 Pod 内部执行以下命令: +# 创建超级管理员账户 (请按照提示操作) +python manage.py createsuperuser + +# (可选) 创建测试数据 +python manage.py create_testdata + +# (可选,如果启用了 ES) 创建索引 +python manage.py rebuild_index + +# 退出 Pod +exit +``` + +至此,您已成功在 Kubernetes 集群上完成了 DjangoBlog 的部署! \ No newline at end of file diff --git a/locale/en/LC_MESSAGES/django.mo b/locale/en/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..f63669f46b3283a84e04098a7338b55f204e7b9d GIT binary patch literal 11097 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 literal 0 HcmV?d00001 diff --git a/locale/en/LC_MESSAGES/django.po b/locale/en/LC_MESSAGES/django.po new file mode 100644 index 0000000..c80b30a --- /dev/null +++ b/locale/en/LC_MESSAGES/django.po @@ -0,0 +1,685 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-09-13 16:02+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: .\accounts\admin.py:12 +msgid "password" +msgstr "password" + +#: .\accounts\admin.py:13 +msgid "Enter password again" +msgstr "Enter password again" + +#: .\accounts\admin.py:24 .\accounts\forms.py:89 +msgid "passwords do not match" +msgstr "passwords do not match" + +#: .\accounts\forms.py:36 +msgid "email already exists" +msgstr "email already exists" + +#: .\accounts\forms.py:46 .\accounts\forms.py:50 +msgid "New password" +msgstr "New password" + +#: .\accounts\forms.py:60 +msgid "Confirm password" +msgstr "Confirm password" + +#: .\accounts\forms.py:70 .\accounts\forms.py:116 +msgid "Email" +msgstr "Email" + +#: .\accounts\forms.py:76 .\accounts\forms.py:80 +msgid "Code" +msgstr "Code" + +#: .\accounts\forms.py:100 .\accounts\tests.py:194 +msgid "email does not exist" +msgstr "email does not exist" + +#: .\accounts\models.py:12 .\oauth\models.py:17 +msgid "nick name" +msgstr "nick name" + +#: .\accounts\models.py:13 .\blog\models.py:29 .\blog\models.py:266 +#: .\blog\models.py:284 .\comments\models.py:13 .\oauth\models.py:23 +#: .\oauth\models.py:53 +msgid "creation time" +msgstr "creation time" + +#: .\accounts\models.py:14 .\comments\models.py:14 .\oauth\models.py:24 +#: .\oauth\models.py:54 +msgid "last modify time" +msgstr "last modify time" + +#: .\accounts\models.py:15 +msgid "create source" +msgstr "create source" + +#: .\accounts\models.py:33 .\djangoblog\logentryadmin.py:81 +msgid "user" +msgstr "user" + +#: .\accounts\tests.py:216 .\accounts\utils.py:39 +msgid "Verification code error" +msgstr "Verification code error" + +#: .\accounts\utils.py:13 +msgid "Verify Email" +msgstr "Verify Email" + +#: .\accounts\utils.py:21 +#, python-format +msgid "" +"You are resetting the password, the verification code is:%(code)s, valid " +"within 5 minutes, please keep it properly" +msgstr "" +"You are resetting the password, the verification code is:%(code)s, valid " +"within 5 minutes, please keep it properly" + +#: .\blog\admin.py:13 .\blog\models.py:92 .\comments\models.py:17 +#: .\oauth\models.py:12 +msgid "author" +msgstr "author" + +#: .\blog\admin.py:53 +msgid "Publish selected articles" +msgstr "Publish selected articles" + +#: .\blog\admin.py:54 +msgid "Draft selected articles" +msgstr "Draft selected articles" + +#: .\blog\admin.py:55 +msgid "Close article comments" +msgstr "Close article comments" + +#: .\blog\admin.py:56 +msgid "Open article comments" +msgstr "Open article comments" + +#: .\blog\admin.py:89 .\blog\models.py:101 .\blog\models.py:183 +#: .\templates\blog\tags\sidebar.html:40 +msgid "category" +msgstr "category" + +#: .\blog\models.py:20 .\blog\models.py:179 .\templates\share_layout\nav.html:8 +msgid "index" +msgstr "index" + +#: .\blog\models.py:21 +msgid "list" +msgstr "list" + +#: .\blog\models.py:22 +msgid "post" +msgstr "post" + +#: .\blog\models.py:23 +msgid "all" +msgstr "all" + +#: .\blog\models.py:24 +msgid "slide" +msgstr "slide" + +#: .\blog\models.py:30 .\blog\models.py:267 .\blog\models.py:285 +msgid "modify time" +msgstr "modify time" + +#: .\blog\models.py:63 +msgid "Draft" +msgstr "Draft" + +#: .\blog\models.py:64 +msgid "Published" +msgstr "Published" + +#: .\blog\models.py:67 +msgid "Open" +msgstr "Open" + +#: .\blog\models.py:68 +msgid "Close" +msgstr "Close" + +#: .\blog\models.py:71 .\comments\admin.py:47 +msgid "Article" +msgstr "Article" + +#: .\blog\models.py:72 +msgid "Page" +msgstr "Page" + +#: .\blog\models.py:74 .\blog\models.py:280 +msgid "title" +msgstr "title" + +#: .\blog\models.py:75 +msgid "body" +msgstr "body" + +#: .\blog\models.py:77 +msgid "publish time" +msgstr "publish time" + +#: .\blog\models.py:79 +msgid "status" +msgstr "status" + +#: .\blog\models.py:84 +msgid "comment status" +msgstr "comment status" + +#: .\blog\models.py:88 .\oauth\models.py:43 +msgid "type" +msgstr "type" + +#: .\blog\models.py:89 +msgid "views" +msgstr "views" + +#: .\blog\models.py:97 .\blog\models.py:258 .\blog\models.py:282 +msgid "order" +msgstr "order" + +#: .\blog\models.py:98 +msgid "show toc" +msgstr "show toc" + +#: .\blog\models.py:105 .\blog\models.py:249 +msgid "tag" +msgstr "tag" + +#: .\blog\models.py:115 .\comments\models.py:21 +msgid "article" +msgstr "article" + +#: .\blog\models.py:171 +msgid "category name" +msgstr "category name" + +#: .\blog\models.py:174 +msgid "parent category" +msgstr "parent category" + +#: .\blog\models.py:234 +msgid "tag name" +msgstr "tag name" + +#: .\blog\models.py:256 +msgid "link name" +msgstr "link name" + +#: .\blog\models.py:257 .\blog\models.py:271 +msgid "link" +msgstr "link" + +#: .\blog\models.py:260 +msgid "is show" +msgstr "is show" + +#: .\blog\models.py:262 +msgid "show type" +msgstr "show type" + +#: .\blog\models.py:281 +msgid "content" +msgstr "content" + +#: .\blog\models.py:283 .\oauth\models.py:52 +msgid "is enable" +msgstr "is enable" + +#: .\blog\models.py:289 +msgid "sidebar" +msgstr "sidebar" + +#: .\blog\models.py:299 +msgid "site name" +msgstr "site name" + +#: .\blog\models.py:305 +msgid "site description" +msgstr "site description" + +#: .\blog\models.py:311 +msgid "site seo description" +msgstr "site seo description" + +#: .\blog\models.py:313 +msgid "site keywords" +msgstr "site keywords" + +#: .\blog\models.py:318 +msgid "article sub length" +msgstr "article sub length" + +#: .\blog\models.py:319 +msgid "sidebar article count" +msgstr "sidebar article count" + +#: .\blog\models.py:320 +msgid "sidebar comment count" +msgstr "sidebar comment count" + +#: .\blog\models.py:321 +msgid "article comment count" +msgstr "article comment count" + +#: .\blog\models.py:322 +msgid "show adsense" +msgstr "show adsense" + +#: .\blog\models.py:324 +msgid "adsense code" +msgstr "adsense code" + +#: .\blog\models.py:325 +msgid "open site comment" +msgstr "open site comment" + +#: .\blog\models.py:352 +msgid "Website configuration" +msgstr "Website configuration" + +#: .\blog\models.py:360 +msgid "There can only be one configuration" +msgstr "There can only be one configuration" + +#: .\blog\views.py:348 +msgid "" +"Sorry, the page you requested is not found, please click the home page to " +"see other?" +msgstr "" +"Sorry, the page you requested is not found, please click the home page to " +"see other?" + +#: .\blog\views.py:356 +msgid "Sorry, the server is busy, please click the home page to see other?" +msgstr "Sorry, the server is busy, please click the home page to see other?" + +#: .\blog\views.py:369 +msgid "Sorry, you do not have permission to access this page?" +msgstr "Sorry, you do not have permission to access this page?" + +#: .\comments\admin.py:15 +msgid "Disable comments" +msgstr "Disable comments" + +#: .\comments\admin.py:16 +msgid "Enable comments" +msgstr "Enable comments" + +#: .\comments\admin.py:46 +msgid "User" +msgstr "User" + +#: .\comments\models.py:25 +msgid "parent comment" +msgstr "parent comment" + +#: .\comments\models.py:29 +msgid "enable" +msgstr "enable" + +#: .\comments\models.py:34 .\templates\blog\tags\article_info.html:30 +msgid "comment" +msgstr "comment" + +#: .\comments\utils.py:13 +msgid "Thanks for your comment" +msgstr "Thanks for your comment" + +#: .\comments\utils.py:15 +#, python-format +msgid "" +"

Thank you very much for your comments on this site

\n" +" You can visit
%(article_title)s\n" +" to review your comments,\n" +" Thank you again!\n" +"
\n" +" If the link above cannot be opened, please copy this " +"link to your browser.\n" +" %(article_url)s" +msgstr "" +"

Thank you very much for your comments on this site

\n" +" You can visit %(article_title)s\n" +" to review your comments,\n" +" Thank you again!\n" +"
\n" +" If the link above cannot be opened, please copy this " +"link to your browser.\n" +" %(article_url)s" + +#: .\comments\utils.py:26 +#, python-format +msgid "" +"Your comment on " +"%(article_title)s
has \n" +" received a reply.
%(comment_body)s\n" +"
\n" +" go check it out!\n" +"
\n" +" If the link above cannot be opened, please copy this " +"link to your browser.\n" +" %(article_url)s\n" +" " +msgstr "" +"Your comment on " +"%(article_title)s
has \n" +" received a reply.
%(comment_body)s\n" +"
\n" +" go check it out!\n" +"
\n" +" If the link above cannot be opened, please copy this " +"link to your browser.\n" +" %(article_url)s\n" +" " + +#: .\djangoblog\logentryadmin.py:63 +msgid "object" +msgstr "object" + +#: .\djangoblog\settings.py:140 +msgid "English" +msgstr "English" + +#: .\djangoblog\settings.py:141 +msgid "Simplified Chinese" +msgstr "Simplified Chinese" + +#: .\djangoblog\settings.py:142 +msgid "Traditional Chinese" +msgstr "Traditional Chinese" + +#: .\oauth\models.py:30 +msgid "oauth user" +msgstr "oauth user" + +#: .\oauth\models.py:37 +msgid "weibo" +msgstr "weibo" + +#: .\oauth\models.py:38 +msgid "google" +msgstr "google" + +#: .\oauth\models.py:48 +msgid "callback url" +msgstr "callback url" + +#: .\oauth\models.py:59 +msgid "already exists" +msgstr "already exists" + +#: .\oauth\views.py:154 +#, python-format +msgid "" +"\n" +"

Congratulations, you have successfully bound your email address. You " +"can use\n" +" %(oauthuser_type)s to directly log in to this website without a " +"password.

\n" +" You are welcome to continue to follow this site, the address is\n" +" %(site)s\n" +" Thank you again!\n" +"
\n" +" If the link above cannot be opened, please copy this link to your " +"browser.\n" +" %(site)s\n" +" " +msgstr "" +"\n" +"

Congratulations, you have successfully bound your email address. You " +"can use\n" +" %(oauthuser_type)s to directly log in to this website without a " +"password.

\n" +" You are welcome to continue to follow this site, the address is\n" +" %(site)s\n" +" Thank you again!\n" +"
\n" +" If the link above cannot be opened, please copy this link to your " +"browser.\n" +" %(site)s\n" +" " + +#: .\oauth\views.py:165 +msgid "Congratulations on your successful binding!" +msgstr "Congratulations on your successful binding!" + +#: .\oauth\views.py:217 +#, python-format +msgid "" +"\n" +"

Please click the link below to bind your email

\n" +"\n" +" %(url)s\n" +"\n" +" Thank you again!\n" +"
\n" +" If the link above cannot be opened, please copy this link " +"to your browser.\n" +"
\n" +" %(url)s\n" +" " +msgstr "" +"\n" +"

Please click the link below to bind your email

\n" +"\n" +" %(url)s\n" +"\n" +" Thank you again!\n" +"
\n" +" If the link above cannot be opened, please copy this link " +"to your browser.\n" +"
\n" +" %(url)s\n" +" " + +#: .\oauth\views.py:228 .\oauth\views.py:240 +msgid "Bind your email" +msgstr "Bind your email" + +#: .\oauth\views.py:242 +msgid "" +"Congratulations, the binding is just one step away. Please log in to your " +"email to check the email to complete the binding. Thank you." +msgstr "" +"Congratulations, the binding is just one step away. Please log in to your " +"email to check the email to complete the binding. Thank you." + +#: .\oauth\views.py:245 +msgid "Binding successful" +msgstr "Binding successful" + +#: .\oauth\views.py:247 +#, python-format +msgid "" +"Congratulations, you have successfully bound your email address. You can use " +"%(oauthuser_type)s to directly log in to this website without a password. " +"You are welcome to continue to follow this site." +msgstr "" +"Congratulations, you have successfully bound your email address. You can use " +"%(oauthuser_type)s to directly log in to this website without a password. " +"You are welcome to continue to follow this site." + +#: .\templates\account\forget_password.html:7 +msgid "forget the password" +msgstr "forget the password" + +#: .\templates\account\forget_password.html:18 +msgid "get verification code" +msgstr "get verification code" + +#: .\templates\account\forget_password.html:19 +msgid "submit" +msgstr "submit" + +#: .\templates\account\login.html:36 +msgid "Create Account" +msgstr "Create Account" + +#: .\templates\account\login.html:42 +#, fuzzy +#| msgid "forget the password" +msgid "Forget Password" +msgstr "forget the password" + +#: .\templates\account\result.html:18 .\templates\blog\tags\sidebar.html:126 +msgid "login" +msgstr "login" + +#: .\templates\account\result.html:22 +msgid "back to the homepage" +msgstr "back to the homepage" + +#: .\templates\blog\article_archives.html:7 +#: .\templates\blog\article_archives.html:24 +msgid "article archive" +msgstr "article archive" + +#: .\templates\blog\article_archives.html:32 +msgid "year" +msgstr "year" + +#: .\templates\blog\article_archives.html:36 +msgid "month" +msgstr "month" + +#: .\templates\blog\tags\article_info.html:12 +msgid "pin to top" +msgstr "pin to top" + +#: .\templates\blog\tags\article_info.html:28 +msgid "comments" +msgstr "comments" + +#: .\templates\blog\tags\article_info.html:58 +msgid "toc" +msgstr "toc" + +#: .\templates\blog\tags\article_meta_info.html:6 +msgid "posted in" +msgstr "posted in" + +#: .\templates\blog\tags\article_meta_info.html:14 +msgid "and tagged" +msgstr "and tagged" + +#: .\templates\blog\tags\article_meta_info.html:25 +msgid "by " +msgstr "by" + +#: .\templates\blog\tags\article_meta_info.html:29 +#, python-format +msgid "" +"\n" +" title=\"View all articles published by " +"%(article.author.username)s\"\n" +" " +msgstr "" +"\n" +" title=\"View all articles published by " +"%(article.author.username)s\"\n" +" " + +#: .\templates\blog\tags\article_meta_info.html:44 +msgid "on" +msgstr "on" + +#: .\templates\blog\tags\article_meta_info.html:54 +msgid "edit" +msgstr "edit" + +#: .\templates\blog\tags\article_pagination.html:4 +msgid "article navigation" +msgstr "article navigation" + +#: .\templates\blog\tags\article_pagination.html:9 +msgid "earlier articles" +msgstr "earlier articles" + +#: .\templates\blog\tags\article_pagination.html:12 +msgid "newer articles" +msgstr "newer articles" + +#: .\templates\blog\tags\article_tag_list.html:5 +msgid "tags" +msgstr "tags" + +#: .\templates\blog\tags\sidebar.html:7 +msgid "search" +msgstr "search" + +#: .\templates\blog\tags\sidebar.html:50 +msgid "recent comments" +msgstr "recent comments" + +#: .\templates\blog\tags\sidebar.html:57 +msgid "published on" +msgstr "published on" + +#: .\templates\blog\tags\sidebar.html:65 +msgid "recent articles" +msgstr "recent articles" + +#: .\templates\blog\tags\sidebar.html:77 +msgid "bookmark" +msgstr "bookmark" + +#: .\templates\blog\tags\sidebar.html:96 +msgid "Tag Cloud" +msgstr "Tag Cloud" + +#: .\templates\blog\tags\sidebar.html:107 +msgid "Welcome to star or fork the source code of this site" +msgstr "Welcome to star or fork the source code of this site" + +#: .\templates\blog\tags\sidebar.html:118 +msgid "Function" +msgstr "Function" + +#: .\templates\blog\tags\sidebar.html:120 +msgid "management site" +msgstr "management site" + +#: .\templates\blog\tags\sidebar.html:122 +msgid "logout" +msgstr "logout" + +#: .\templates\blog\tags\sidebar.html:129 +msgid "Track record" +msgstr "Track record" + +#: .\templates\blog\tags\sidebar.html:135 +msgid "Click me to return to the top" +msgstr "Click me to return to the top" + +#: .\templates\oauth\oauth_applications.html:5 +#| msgid "login" +msgid "quick login" +msgstr "quick login" + +#: .\templates\share_layout\nav.html:26 +msgid "Article archive" +msgstr "Article archive" diff --git a/locale/zh_Hans/LC_MESSAGES/django.mo b/locale/zh_Hans/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..a2d36e98a180a2d9f413841d0cfa0c5f85654f63 GIT binary patch literal 10321 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, YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-09-13 16:02+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: .\accounts\admin.py:12 +msgid "password" +msgstr "密码" + +#: .\accounts\admin.py:13 +msgid "Enter password again" +msgstr "再次输入密码" + +#: .\accounts\admin.py:24 .\accounts\forms.py:89 +msgid "passwords do not match" +msgstr "密码不匹配" + +#: .\accounts\forms.py:36 +msgid "email already exists" +msgstr "邮箱已存在" + +#: .\accounts\forms.py:46 .\accounts\forms.py:50 +msgid "New password" +msgstr "新密码" + +#: .\accounts\forms.py:60 +msgid "Confirm password" +msgstr "确认密码" + +#: .\accounts\forms.py:70 .\accounts\forms.py:116 +msgid "Email" +msgstr "邮箱" + +#: .\accounts\forms.py:76 .\accounts\forms.py:80 +msgid "Code" +msgstr "验证码" + +#: .\accounts\forms.py:100 .\accounts\tests.py:194 +msgid "email does not exist" +msgstr "邮箱不存在" + +#: .\accounts\models.py:12 .\oauth\models.py:17 +msgid "nick name" +msgstr "昵称" + +#: .\accounts\models.py:13 .\blog\models.py:29 .\blog\models.py:266 +#: .\blog\models.py:284 .\comments\models.py:13 .\oauth\models.py:23 +#: .\oauth\models.py:53 +msgid "creation time" +msgstr "创建时间" + +#: .\accounts\models.py:14 .\comments\models.py:14 .\oauth\models.py:24 +#: .\oauth\models.py:54 +msgid "last modify time" +msgstr "最后修改时间" + +#: .\accounts\models.py:15 +msgid "create source" +msgstr "来源" + +#: .\accounts\models.py:33 .\djangoblog\logentryadmin.py:81 +msgid "user" +msgstr "用户" + +#: .\accounts\tests.py:216 .\accounts\utils.py:39 +msgid "Verification code error" +msgstr "验证码错误" + +#: .\accounts\utils.py:13 +msgid "Verify Email" +msgstr "验证邮箱" + +#: .\accounts\utils.py:21 +#, python-format +msgid "" +"You are resetting the password, the verification code is:%(code)s, valid " +"within 5 minutes, please keep it properly" +msgstr "您正在重置密码,验证码为:%(code)s,5分钟内有效 请妥善保管." + +#: .\blog\admin.py:13 .\blog\models.py:92 .\comments\models.py:17 +#: .\oauth\models.py:12 +msgid "author" +msgstr "作者" + +#: .\blog\admin.py:53 +msgid "Publish selected articles" +msgstr "发布选中的文章" + +#: .\blog\admin.py:54 +msgid "Draft selected articles" +msgstr "选中文章设为草稿" + +#: .\blog\admin.py:55 +msgid "Close article comments" +msgstr "关闭文章评论" + +#: .\blog\admin.py:56 +msgid "Open article comments" +msgstr "打开文章评论" + +#: .\blog\admin.py:89 .\blog\models.py:101 .\blog\models.py:183 +#: .\templates\blog\tags\sidebar.html:40 +msgid "category" +msgstr "分类目录" + +#: .\blog\models.py:20 .\blog\models.py:179 .\templates\share_layout\nav.html:8 +msgid "index" +msgstr "首页" + +#: .\blog\models.py:21 +msgid "list" +msgstr "列表" + +#: .\blog\models.py:22 +msgid "post" +msgstr "文章" + +#: .\blog\models.py:23 +msgid "all" +msgstr "所有" + +#: .\blog\models.py:24 +msgid "slide" +msgstr "侧边栏" + +#: .\blog\models.py:30 .\blog\models.py:267 .\blog\models.py:285 +msgid "modify time" +msgstr "修改时间" + +#: .\blog\models.py:63 +msgid "Draft" +msgstr "草稿" + +#: .\blog\models.py:64 +msgid "Published" +msgstr "发布" + +#: .\blog\models.py:67 +msgid "Open" +msgstr "打开" + +#: .\blog\models.py:68 +msgid "Close" +msgstr "关闭" + +#: .\blog\models.py:71 .\comments\admin.py:47 +msgid "Article" +msgstr "文章" + +#: .\blog\models.py:72 +msgid "Page" +msgstr "页面" + +#: .\blog\models.py:74 .\blog\models.py:280 +msgid "title" +msgstr "标题" + +#: .\blog\models.py:75 +msgid "body" +msgstr "内容" + +#: .\blog\models.py:77 +msgid "publish time" +msgstr "发布时间" + +#: .\blog\models.py:79 +msgid "status" +msgstr "状态" + +#: .\blog\models.py:84 +msgid "comment status" +msgstr "评论状态" + +#: .\blog\models.py:88 .\oauth\models.py:43 +msgid "type" +msgstr "类型" + +#: .\blog\models.py:89 +msgid "views" +msgstr "阅读量" + +#: .\blog\models.py:97 .\blog\models.py:258 .\blog\models.py:282 +msgid "order" +msgstr "排序" + +#: .\blog\models.py:98 +msgid "show toc" +msgstr "显示目录" + +#: .\blog\models.py:105 .\blog\models.py:249 +msgid "tag" +msgstr "标签" + +#: .\blog\models.py:115 .\comments\models.py:21 +msgid "article" +msgstr "文章" + +#: .\blog\models.py:171 +msgid "category name" +msgstr "分类名" + +#: .\blog\models.py:174 +msgid "parent category" +msgstr "上级分类" + +#: .\blog\models.py:234 +msgid "tag name" +msgstr "标签名" + +#: .\blog\models.py:256 +msgid "link name" +msgstr "链接名" + +#: .\blog\models.py:257 .\blog\models.py:271 +msgid "link" +msgstr "链接" + +#: .\blog\models.py:260 +msgid "is show" +msgstr "是否显示" + +#: .\blog\models.py:262 +msgid "show type" +msgstr "显示类型" + +#: .\blog\models.py:281 +msgid "content" +msgstr "内容" + +#: .\blog\models.py:283 .\oauth\models.py:52 +msgid "is enable" +msgstr "是否启用" + +#: .\blog\models.py:289 +msgid "sidebar" +msgstr "侧边栏" + +#: .\blog\models.py:299 +msgid "site name" +msgstr "站点名称" + +#: .\blog\models.py:305 +msgid "site description" +msgstr "站点描述" + +#: .\blog\models.py:311 +msgid "site seo description" +msgstr "站点SEO描述" + +#: .\blog\models.py:313 +msgid "site keywords" +msgstr "关键字" + +#: .\blog\models.py:318 +msgid "article sub length" +msgstr "文章摘要长度" + +#: .\blog\models.py:319 +msgid "sidebar article count" +msgstr "侧边栏文章数目" + +#: .\blog\models.py:320 +msgid "sidebar comment count" +msgstr "侧边栏评论数目" + +#: .\blog\models.py:321 +msgid "article comment count" +msgstr "文章页面默认显示评论数目" + +#: .\blog\models.py:322 +msgid "show adsense" +msgstr "是否显示广告" + +#: .\blog\models.py:324 +msgid "adsense code" +msgstr "广告内容" + +#: .\blog\models.py:325 +msgid "open site comment" +msgstr "公共头部" + +#: .\blog\models.py:352 +msgid "Website configuration" +msgstr "网站配置" + +#: .\blog\models.py:360 +msgid "There can only be one configuration" +msgstr "只能有一个配置" + +#: .\blog\views.py:348 +msgid "" +"Sorry, the page you requested is not found, please click the home page to " +"see other?" +msgstr "抱歉,你所访问的页面找不到,请点击首页看看别的?" + +#: .\blog\views.py:356 +msgid "Sorry, the server is busy, please click the home page to see other?" +msgstr "抱歉,服务出错了,请点击首页看看别的?" + +#: .\blog\views.py:369 +msgid "Sorry, you do not have permission to access this page?" +msgstr "抱歉,你没用权限访问此页面。" + +#: .\comments\admin.py:15 +msgid "Disable comments" +msgstr "禁用评论" + +#: .\comments\admin.py:16 +msgid "Enable comments" +msgstr "启用评论" + +#: .\comments\admin.py:46 +msgid "User" +msgstr "用户" + +#: .\comments\models.py:25 +msgid "parent comment" +msgstr "上级评论" + +#: .\comments\models.py:29 +msgid "enable" +msgstr "启用" + +#: .\comments\models.py:34 .\templates\blog\tags\article_info.html:30 +msgid "comment" +msgstr "评论" + +#: .\comments\utils.py:13 +msgid "Thanks for your comment" +msgstr "感谢你的评论" + +#: .\comments\utils.py:15 +#, python-format +msgid "" +"

Thank you very much for your comments on this site

\n" +" You can visit %(article_title)s\n" +" to review your comments,\n" +" Thank you again!\n" +"
\n" +" If the link above cannot be opened, please copy this " +"link to your browser.\n" +" %(article_url)s" +msgstr "" +"

非常感谢您对此网站的评论

\n" +" 您可以访问%(article_title)s\n" +"查看您的评论,\n" +"再次感谢您!\n" +"
\n" +" 如果上面的链接打不开,请复制此链接链接到您的浏览器。\n" +"%(article_url)s" + +#: .\comments\utils.py:26 +#, python-format +msgid "" +"Your comment on " +"%(article_title)s
has \n" +" received a reply.
%(comment_body)s\n" +"
\n" +" go check it out!\n" +"
\n" +" If the link above cannot be opened, please copy this " +"link to your browser.\n" +" %(article_url)s\n" +" " +msgstr "" +"您对 %(article_title)s
" +"的评论有\n" +" 收到回复。
%(comment_body)s\n" +"
\n" +"快去看看吧!\n" +"
\n" +" 如果上面的链接打不开,请复制此链接链接到您的浏览器。\n" +" %(article_url)s\n" +" " + +#: .\djangoblog\logentryadmin.py:63 +msgid "object" +msgstr "对象" + +#: .\djangoblog\settings.py:140 +msgid "English" +msgstr "英文" + +#: .\djangoblog\settings.py:141 +msgid "Simplified Chinese" +msgstr "简体中文" + +#: .\djangoblog\settings.py:142 +msgid "Traditional Chinese" +msgstr "繁体中文" + +#: .\oauth\models.py:30 +msgid "oauth user" +msgstr "第三方用户" + +#: .\oauth\models.py:37 +msgid "weibo" +msgstr "微博" + +#: .\oauth\models.py:38 +msgid "google" +msgstr "谷歌" + +#: .\oauth\models.py:48 +msgid "callback url" +msgstr "回调地址" + +#: .\oauth\models.py:59 +msgid "already exists" +msgstr "已经存在" + +#: .\oauth\views.py:154 +#, python-format +msgid "" +"\n" +"

Congratulations, you have successfully bound your email address. You " +"can use\n" +" %(oauthuser_type)s to directly log in to this website without a " +"password.

\n" +" You are welcome to continue to follow this site, the address is\n" +" %(site)s\n" +" Thank you again!\n" +"
\n" +" If the link above cannot be opened, please copy this link to your " +"browser.\n" +" %(site)s\n" +" " +msgstr "" +"\n" +"

恭喜你已经绑定成功 你可以使用\n" +" %(oauthuser_type)s 来免密登录本站

\n" +" 欢迎继续关注本站, 地址是\n" +" %(site)s\n" +" 再次感谢你\n" +"
\n" +" 如果上面链接无法打开,请复制此链接到你的浏览器 \n" +" %(site)s\n" +" " + +#: .\oauth\views.py:165 +msgid "Congratulations on your successful binding!" +msgstr "恭喜你绑定成功" + +#: .\oauth\views.py:217 +#, python-format +msgid "" +"\n" +"

Please click the link below to bind your email

\n" +"\n" +" %(url)s\n" +"\n" +" Thank you again!\n" +"
\n" +" If the link above cannot be opened, please copy this link " +"to your browser.\n" +"
\n" +" %(url)s\n" +" " +msgstr "" +"\n" +"

请点击下面的链接绑定您的邮箱

\n" +"\n" +" %(url)s\n" +"\n" +"再次感谢您!\n" +"
\n" +"如果上面的链接打不开,请复制此链接到您的浏览器。\n" +"%(url)s\n" +" " + +#: .\oauth\views.py:228 .\oauth\views.py:240 +msgid "Bind your email" +msgstr "绑定邮箱" + +#: .\oauth\views.py:242 +msgid "" +"Congratulations, the binding is just one step away. Please log in to your " +"email to check the email to complete the binding. Thank you." +msgstr "恭喜您,还差一步就绑定成功了,请登录您的邮箱查看邮件完成绑定,谢谢。" + +#: .\oauth\views.py:245 +msgid "Binding successful" +msgstr "绑定成功" + +#: .\oauth\views.py:247 +#, python-format +msgid "" +"Congratulations, you have successfully bound your email address. You can use " +"%(oauthuser_type)s to directly log in to this website without a password. " +"You are welcome to continue to follow this site." +msgstr "" +"恭喜您绑定成功,您以后可以使用%(oauthuser_type)s来直接免密码登录本站啦,感谢" +"您对本站对关注。" + +#: .\templates\account\forget_password.html:7 +msgid "forget the password" +msgstr "忘记密码" + +#: .\templates\account\forget_password.html:18 +msgid "get verification code" +msgstr "获取验证码" + +#: .\templates\account\forget_password.html:19 +msgid "submit" +msgstr "提交" + +#: .\templates\account\login.html:36 +msgid "Create Account" +msgstr "创建账号" + +#: .\templates\account\login.html:42 +#| msgid "forget the password" +msgid "Forget Password" +msgstr "忘记密码" + +#: .\templates\account\result.html:18 .\templates\blog\tags\sidebar.html:126 +msgid "login" +msgstr "登录" + +#: .\templates\account\result.html:22 +msgid "back to the homepage" +msgstr "返回首页吧" + +#: .\templates\blog\article_archives.html:7 +#: .\templates\blog\article_archives.html:24 +msgid "article archive" +msgstr "文章归档" + +#: .\templates\blog\article_archives.html:32 +msgid "year" +msgstr "年" + +#: .\templates\blog\article_archives.html:36 +msgid "month" +msgstr "月" + +#: .\templates\blog\tags\article_info.html:12 +msgid "pin to top" +msgstr "置顶" + +#: .\templates\blog\tags\article_info.html:28 +msgid "comments" +msgstr "评论" + +#: .\templates\blog\tags\article_info.html:58 +msgid "toc" +msgstr "目录" + +#: .\templates\blog\tags\article_meta_info.html:6 +msgid "posted in" +msgstr "发布于" + +#: .\templates\blog\tags\article_meta_info.html:14 +msgid "and tagged" +msgstr "并标记为" + +#: .\templates\blog\tags\article_meta_info.html:25 +msgid "by " +msgstr "由" + +#: .\templates\blog\tags\article_meta_info.html:29 +#, python-format +msgid "" +"\n" +" title=\"View all articles published by " +"%(article.author.username)s\"\n" +" " +msgstr "" +"\n" +" title=\"查看所有由 %(article.author.username)s\"发布的文章\n" +" " + +#: .\templates\blog\tags\article_meta_info.html:44 +msgid "on" +msgstr "在" + +#: .\templates\blog\tags\article_meta_info.html:54 +msgid "edit" +msgstr "编辑" + +#: .\templates\blog\tags\article_pagination.html:4 +msgid "article navigation" +msgstr "文章导航" + +#: .\templates\blog\tags\article_pagination.html:9 +msgid "earlier articles" +msgstr "早期文章" + +#: .\templates\blog\tags\article_pagination.html:12 +msgid "newer articles" +msgstr "较新文章" + +#: .\templates\blog\tags\article_tag_list.html:5 +msgid "tags" +msgstr "标签" + +#: .\templates\blog\tags\sidebar.html:7 +msgid "search" +msgstr "搜索" + +#: .\templates\blog\tags\sidebar.html:50 +msgid "recent comments" +msgstr "近期评论" + +#: .\templates\blog\tags\sidebar.html:57 +msgid "published on" +msgstr "发表于" + +#: .\templates\blog\tags\sidebar.html:65 +msgid "recent articles" +msgstr "近期文章" + +#: .\templates\blog\tags\sidebar.html:77 +msgid "bookmark" +msgstr "书签" + +#: .\templates\blog\tags\sidebar.html:96 +msgid "Tag Cloud" +msgstr "标签云" + +#: .\templates\blog\tags\sidebar.html:107 +msgid "Welcome to star or fork the source code of this site" +msgstr "欢迎您STAR或者FORK本站源代码" + +#: .\templates\blog\tags\sidebar.html:118 +msgid "Function" +msgstr "功能" + +#: .\templates\blog\tags\sidebar.html:120 +msgid "management site" +msgstr "管理站点" + +#: .\templates\blog\tags\sidebar.html:122 +msgid "logout" +msgstr "登出" + +#: .\templates\blog\tags\sidebar.html:129 +msgid "Track record" +msgstr "运动轨迹记录" + +#: .\templates\blog\tags\sidebar.html:135 +msgid "Click me to return to the top" +msgstr "点我返回顶部" + +#: .\templates\oauth\oauth_applications.html:5 +#| msgid "login" +msgid "quick login" +msgstr "快捷登录" + +#: .\templates\share_layout\nav.html:26 +msgid "Article archive" +msgstr "文章归档" diff --git a/locale/zh_Hant/LC_MESSAGES/django.mo b/locale/zh_Hant/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..fe2ea17dc2636742b9c3b8d4eddb6293ee3b7290 GIT binary patch literal 10268 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 literal 0 HcmV?d00001 diff --git a/locale/zh_Hant/LC_MESSAGES/django.po b/locale/zh_Hant/LC_MESSAGES/django.po new file mode 100644 index 0000000..a2920ce --- /dev/null +++ b/locale/zh_Hant/LC_MESSAGES/django.po @@ -0,0 +1,668 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-09-13 16:02+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: .\accounts\admin.py:12 +msgid "password" +msgstr "密碼" + +#: .\accounts\admin.py:13 +msgid "Enter password again" +msgstr "再次輸入密碼" + +#: .\accounts\admin.py:24 .\accounts\forms.py:89 +msgid "passwords do not match" +msgstr "密碼不匹配" + +#: .\accounts\forms.py:36 +msgid "email already exists" +msgstr "郵箱已存在" + +#: .\accounts\forms.py:46 .\accounts\forms.py:50 +msgid "New password" +msgstr "新密碼" + +#: .\accounts\forms.py:60 +msgid "Confirm password" +msgstr "確認密碼" + +#: .\accounts\forms.py:70 .\accounts\forms.py:116 +msgid "Email" +msgstr "郵箱" + +#: .\accounts\forms.py:76 .\accounts\forms.py:80 +msgid "Code" +msgstr "驗證碼" + +#: .\accounts\forms.py:100 .\accounts\tests.py:194 +msgid "email does not exist" +msgstr "郵箱不存在" + +#: .\accounts\models.py:12 .\oauth\models.py:17 +msgid "nick name" +msgstr "昵稱" + +#: .\accounts\models.py:13 .\blog\models.py:29 .\blog\models.py:266 +#: .\blog\models.py:284 .\comments\models.py:13 .\oauth\models.py:23 +#: .\oauth\models.py:53 +msgid "creation time" +msgstr "創建時間" + +#: .\accounts\models.py:14 .\comments\models.py:14 .\oauth\models.py:24 +#: .\oauth\models.py:54 +msgid "last modify time" +msgstr "最後修改時間" + +#: .\accounts\models.py:15 +msgid "create source" +msgstr "來源" + +#: .\accounts\models.py:33 .\djangoblog\logentryadmin.py:81 +msgid "user" +msgstr "用戶" + +#: .\accounts\tests.py:216 .\accounts\utils.py:39 +msgid "Verification code error" +msgstr "驗證碼錯誤" + +#: .\accounts\utils.py:13 +msgid "Verify Email" +msgstr "驗證郵箱" + +#: .\accounts\utils.py:21 +#, python-format +msgid "" +"You are resetting the password, the verification code is:%(code)s, valid " +"within 5 minutes, please keep it properly" +msgstr "您正在重置密碼,驗證碼為:%(code)s,5分鐘內有效 請妥善保管." + +#: .\blog\admin.py:13 .\blog\models.py:92 .\comments\models.py:17 +#: .\oauth\models.py:12 +msgid "author" +msgstr "作者" + +#: .\blog\admin.py:53 +msgid "Publish selected articles" +msgstr "發布選中的文章" + +#: .\blog\admin.py:54 +msgid "Draft selected articles" +msgstr "選中文章設為草稿" + +#: .\blog\admin.py:55 +msgid "Close article comments" +msgstr "關閉文章評論" + +#: .\blog\admin.py:56 +msgid "Open article comments" +msgstr "打開文章評論" + +#: .\blog\admin.py:89 .\blog\models.py:101 .\blog\models.py:183 +#: .\templates\blog\tags\sidebar.html:40 +msgid "category" +msgstr "分類目錄" + +#: .\blog\models.py:20 .\blog\models.py:179 .\templates\share_layout\nav.html:8 +msgid "index" +msgstr "首頁" + +#: .\blog\models.py:21 +msgid "list" +msgstr "列表" + +#: .\blog\models.py:22 +msgid "post" +msgstr "文章" + +#: .\blog\models.py:23 +msgid "all" +msgstr "所有" + +#: .\blog\models.py:24 +msgid "slide" +msgstr "側邊欄" + +#: .\blog\models.py:30 .\blog\models.py:267 .\blog\models.py:285 +msgid "modify time" +msgstr "修改時間" + +#: .\blog\models.py:63 +msgid "Draft" +msgstr "草稿" + +#: .\blog\models.py:64 +msgid "Published" +msgstr "發布" + +#: .\blog\models.py:67 +msgid "Open" +msgstr "打開" + +#: .\blog\models.py:68 +msgid "Close" +msgstr "關閉" + +#: .\blog\models.py:71 .\comments\admin.py:47 +msgid "Article" +msgstr "文章" + +#: .\blog\models.py:72 +msgid "Page" +msgstr "頁面" + +#: .\blog\models.py:74 .\blog\models.py:280 +msgid "title" +msgstr "標題" + +#: .\blog\models.py:75 +msgid "body" +msgstr "內容" + +#: .\blog\models.py:77 +msgid "publish time" +msgstr "發布時間" + +#: .\blog\models.py:79 +msgid "status" +msgstr "狀態" + +#: .\blog\models.py:84 +msgid "comment status" +msgstr "評論狀態" + +#: .\blog\models.py:88 .\oauth\models.py:43 +msgid "type" +msgstr "類型" + +#: .\blog\models.py:89 +msgid "views" +msgstr "閱讀量" + +#: .\blog\models.py:97 .\blog\models.py:258 .\blog\models.py:282 +msgid "order" +msgstr "排序" + +#: .\blog\models.py:98 +msgid "show toc" +msgstr "顯示目錄" + +#: .\blog\models.py:105 .\blog\models.py:249 +msgid "tag" +msgstr "標簽" + +#: .\blog\models.py:115 .\comments\models.py:21 +msgid "article" +msgstr "文章" + +#: .\blog\models.py:171 +msgid "category name" +msgstr "分類名" + +#: .\blog\models.py:174 +msgid "parent category" +msgstr "上級分類" + +#: .\blog\models.py:234 +msgid "tag name" +msgstr "標簽名" + +#: .\blog\models.py:256 +msgid "link name" +msgstr "鏈接名" + +#: .\blog\models.py:257 .\blog\models.py:271 +msgid "link" +msgstr "鏈接" + +#: .\blog\models.py:260 +msgid "is show" +msgstr "是否顯示" + +#: .\blog\models.py:262 +msgid "show type" +msgstr "顯示類型" + +#: .\blog\models.py:281 +msgid "content" +msgstr "內容" + +#: .\blog\models.py:283 .\oauth\models.py:52 +msgid "is enable" +msgstr "是否啟用" + +#: .\blog\models.py:289 +msgid "sidebar" +msgstr "側邊欄" + +#: .\blog\models.py:299 +msgid "site name" +msgstr "站點名稱" + +#: .\blog\models.py:305 +msgid "site description" +msgstr "站點描述" + +#: .\blog\models.py:311 +msgid "site seo description" +msgstr "站點SEO描述" + +#: .\blog\models.py:313 +msgid "site keywords" +msgstr "關鍵字" + +#: .\blog\models.py:318 +msgid "article sub length" +msgstr "文章摘要長度" + +#: .\blog\models.py:319 +msgid "sidebar article count" +msgstr "側邊欄文章數目" + +#: .\blog\models.py:320 +msgid "sidebar comment count" +msgstr "側邊欄評論數目" + +#: .\blog\models.py:321 +msgid "article comment count" +msgstr "文章頁面默認顯示評論數目" + +#: .\blog\models.py:322 +msgid "show adsense" +msgstr "是否顯示廣告" + +#: .\blog\models.py:324 +msgid "adsense code" +msgstr "廣告內容" + +#: .\blog\models.py:325 +msgid "open site comment" +msgstr "公共頭部" + +#: .\blog\models.py:352 +msgid "Website configuration" +msgstr "網站配置" + +#: .\blog\models.py:360 +msgid "There can only be one configuration" +msgstr "只能有一個配置" + +#: .\blog\views.py:348 +msgid "" +"Sorry, the page you requested is not found, please click the home page to " +"see other?" +msgstr "抱歉,你所訪問的頁面找不到,請點擊首頁看看別的?" + +#: .\blog\views.py:356 +msgid "Sorry, the server is busy, please click the home page to see other?" +msgstr "抱歉,服務出錯了,請點擊首頁看看別的?" + +#: .\blog\views.py:369 +msgid "Sorry, you do not have permission to access this page?" +msgstr "抱歉,你沒用權限訪問此頁面。" + +#: .\comments\admin.py:15 +msgid "Disable comments" +msgstr "禁用評論" + +#: .\comments\admin.py:16 +msgid "Enable comments" +msgstr "啟用評論" + +#: .\comments\admin.py:46 +msgid "User" +msgstr "用戶" + +#: .\comments\models.py:25 +msgid "parent comment" +msgstr "上級評論" + +#: .\comments\models.py:29 +msgid "enable" +msgstr "啟用" + +#: .\comments\models.py:34 .\templates\blog\tags\article_info.html:30 +msgid "comment" +msgstr "評論" + +#: .\comments\utils.py:13 +msgid "Thanks for your comment" +msgstr "感謝你的評論" + +#: .\comments\utils.py:15 +#, python-format +msgid "" +"

Thank you very much for your comments on this site

\n" +" You can visit %(article_title)s\n" +" to review your comments,\n" +" Thank you again!\n" +"
\n" +" If the link above cannot be opened, please copy this " +"link to your browser.\n" +" %(article_url)s" +msgstr "" +"

非常感謝您對此網站的評論

\n" +" 您可以訪問%(article_title)s\n" +"查看您的評論,\n" +"再次感謝您!\n" +"
\n" +" 如果上面的鏈接打不開,請復製此鏈接鏈接到您的瀏覽器。\n" +"%(article_url)s" + +#: .\comments\utils.py:26 +#, python-format +msgid "" +"Your comment on " +"%(article_title)s
has \n" +" received a reply.
%(comment_body)s\n" +"
\n" +" go check it out!\n" +"
\n" +" If the link above cannot be opened, please copy this " +"link to your browser.\n" +" %(article_url)s\n" +" " +msgstr "" +"您對 %(article_title)s
" +"的評論有\n" +" 收到回復。
%(comment_body)s\n" +"
\n" +"快去看看吧!\n" +"
\n" +" 如果上面的鏈接打不開,請復製此鏈接鏈接到您的瀏覽器。\n" +" %(article_url)s\n" +" " + +#: .\djangoblog\logentryadmin.py:63 +msgid "object" +msgstr "對象" + +#: .\djangoblog\settings.py:140 +msgid "English" +msgstr "英文" + +#: .\djangoblog\settings.py:141 +msgid "Simplified Chinese" +msgstr "簡體中文" + +#: .\djangoblog\settings.py:142 +msgid "Traditional Chinese" +msgstr "繁體中文" + +#: .\oauth\models.py:30 +msgid "oauth user" +msgstr "第三方用戶" + +#: .\oauth\models.py:37 +msgid "weibo" +msgstr "微博" + +#: .\oauth\models.py:38 +msgid "google" +msgstr "谷歌" + +#: .\oauth\models.py:48 +msgid "callback url" +msgstr "回調地址" + +#: .\oauth\models.py:59 +msgid "already exists" +msgstr "已經存在" + +#: .\oauth\views.py:154 +#, python-format +msgid "" +"\n" +"

Congratulations, you have successfully bound your email address. You " +"can use\n" +" %(oauthuser_type)s to directly log in to this website without a " +"password.

\n" +" You are welcome to continue to follow this site, the address is\n" +" %(site)s\n" +" Thank you again!\n" +"
\n" +" If the link above cannot be opened, please copy this link to your " +"browser.\n" +" %(site)s\n" +" " +msgstr "" +"\n" +"

恭喜你已經綁定成功 你可以使用\n" +" %(oauthuser_type)s 來免密登錄本站

\n" +" 歡迎繼續關註本站, 地址是\n" +" %(site)s\n" +" 再次感謝你\n" +"
\n" +" 如果上面鏈接無法打開,請復製此鏈接到你的瀏覽器 \n" +" %(site)s\n" +" " + +#: .\oauth\views.py:165 +msgid "Congratulations on your successful binding!" +msgstr "恭喜你綁定成功" + +#: .\oauth\views.py:217 +#, python-format +msgid "" +"\n" +"

Please click the link below to bind your email

\n" +"\n" +" %(url)s\n" +"\n" +" Thank you again!\n" +"
\n" +" If the link above cannot be opened, please copy this link " +"to your browser.\n" +"
\n" +" %(url)s\n" +" " +msgstr "" +"\n" +"

請點擊下面的鏈接綁定您的郵箱

\n" +"\n" +" %(url)s\n" +"\n" +"再次感謝您!\n" +"
\n" +"如果上面的鏈接打不開,請復製此鏈接到您的瀏覽器。\n" +"%(url)s\n" +" " + +#: .\oauth\views.py:228 .\oauth\views.py:240 +msgid "Bind your email" +msgstr "綁定郵箱" + +#: .\oauth\views.py:242 +msgid "" +"Congratulations, the binding is just one step away. Please log in to your " +"email to check the email to complete the binding. Thank you." +msgstr "恭喜您,還差一步就綁定成功了,請登錄您的郵箱查看郵件完成綁定,謝謝。" + +#: .\oauth\views.py:245 +msgid "Binding successful" +msgstr "綁定成功" + +#: .\oauth\views.py:247 +#, python-format +msgid "" +"Congratulations, you have successfully bound your email address. You can use " +"%(oauthuser_type)s to directly log in to this website without a password. " +"You are welcome to continue to follow this site." +msgstr "" +"恭喜您綁定成功,您以後可以使用%(oauthuser_type)s來直接免密碼登錄本站啦,感謝" +"您對本站對關註。" + +#: .\templates\account\forget_password.html:7 +msgid "forget the password" +msgstr "忘記密碼" + +#: .\templates\account\forget_password.html:18 +msgid "get verification code" +msgstr "獲取驗證碼" + +#: .\templates\account\forget_password.html:19 +msgid "submit" +msgstr "提交" + +#: .\templates\account\login.html:36 +msgid "Create Account" +msgstr "創建賬號" + +#: .\templates\account\login.html:42 +#, fuzzy +#| msgid "forget the password" +msgid "Forget Password" +msgstr "忘記密碼" + +#: .\templates\account\result.html:18 .\templates\blog\tags\sidebar.html:126 +msgid "login" +msgstr "登錄" + +#: .\templates\account\result.html:22 +msgid "back to the homepage" +msgstr "返回首頁吧" + +#: .\templates\blog\article_archives.html:7 +#: .\templates\blog\article_archives.html:24 +msgid "article archive" +msgstr "文章歸檔" + +#: .\templates\blog\article_archives.html:32 +msgid "year" +msgstr "年" + +#: .\templates\blog\article_archives.html:36 +msgid "month" +msgstr "月" + +#: .\templates\blog\tags\article_info.html:12 +msgid "pin to top" +msgstr "置頂" + +#: .\templates\blog\tags\article_info.html:28 +msgid "comments" +msgstr "評論" + +#: .\templates\blog\tags\article_info.html:58 +msgid "toc" +msgstr "目錄" + +#: .\templates\blog\tags\article_meta_info.html:6 +msgid "posted in" +msgstr "發布於" + +#: .\templates\blog\tags\article_meta_info.html:14 +msgid "and tagged" +msgstr "並標記為" + +#: .\templates\blog\tags\article_meta_info.html:25 +msgid "by " +msgstr "由" + +#: .\templates\blog\tags\article_meta_info.html:29 +#, python-format +msgid "" +"\n" +" title=\"View all articles published by " +"%(article.author.username)s\"\n" +" " +msgstr "" +"\n" +" title=\"查看所有由 %(article.author.username)s\"發布的文章\n" +" " + +#: .\templates\blog\tags\article_meta_info.html:44 +msgid "on" +msgstr "在" + +#: .\templates\blog\tags\article_meta_info.html:54 +msgid "edit" +msgstr "編輯" + +#: .\templates\blog\tags\article_pagination.html:4 +msgid "article navigation" +msgstr "文章導航" + +#: .\templates\blog\tags\article_pagination.html:9 +msgid "earlier articles" +msgstr "早期文章" + +#: .\templates\blog\tags\article_pagination.html:12 +msgid "newer articles" +msgstr "較新文章" + +#: .\templates\blog\tags\article_tag_list.html:5 +msgid "tags" +msgstr "標簽" + +#: .\templates\blog\tags\sidebar.html:7 +msgid "search" +msgstr "搜索" + +#: .\templates\blog\tags\sidebar.html:50 +msgid "recent comments" +msgstr "近期評論" + +#: .\templates\blog\tags\sidebar.html:57 +msgid "published on" +msgstr "發表於" + +#: .\templates\blog\tags\sidebar.html:65 +msgid "recent articles" +msgstr "近期文章" + +#: .\templates\blog\tags\sidebar.html:77 +msgid "bookmark" +msgstr "書簽" + +#: .\templates\blog\tags\sidebar.html:96 +msgid "Tag Cloud" +msgstr "標簽雲" + +#: .\templates\blog\tags\sidebar.html:107 +msgid "Welcome to star or fork the source code of this site" +msgstr "歡迎您STAR或者FORK本站源代碼" + +#: .\templates\blog\tags\sidebar.html:118 +msgid "Function" +msgstr "功能" + +#: .\templates\blog\tags\sidebar.html:120 +msgid "management site" +msgstr "管理站點" + +#: .\templates\blog\tags\sidebar.html:122 +msgid "logout" +msgstr "登出" + +#: .\templates\blog\tags\sidebar.html:129 +msgid "Track record" +msgstr "運動軌跡記錄" + +#: .\templates\blog\tags\sidebar.html:135 +msgid "Click me to return to the top" +msgstr "點我返回頂部" + +#: .\templates\oauth\oauth_applications.html:5 +#| msgid "login" +msgid "quick login" +msgstr "快捷登錄" + +#: .\templates\share_layout\nav.html:26 +msgid "Article archive" +msgstr "文章歸檔" diff --git a/manage.py b/manage.py new file mode 100644 index 0000000..919ba74 --- /dev/null +++ b/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +import os +import sys + +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "djangoblog.settings") + try: + from django.core.management import execute_from_command_line + except ImportError: + # The above import may fail for some other reason. Ensure that the + # issue is really that Django is missing to avoid masking other + # exceptions on Python 2. + try: + import django + except ImportError: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) + raise + execute_from_command_line(sys.argv) diff --git a/oauth/__init__.py b/oauth/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/oauth/admin.py b/oauth/admin.py new file mode 100644 index 0000000..57eab5f --- /dev/null +++ b/oauth/admin.py @@ -0,0 +1,54 @@ +import logging + +from django.contrib import admin +# Register your models here. +from django.urls import reverse +from django.utils.html import format_html + +logger = logging.getLogger(__name__) + + +class OAuthUserAdmin(admin.ModelAdmin): + search_fields = ('nickname', 'email') + list_per_page = 20 + list_display = ( + 'id', + 'nickname', + 'link_to_usermodel', + 'show_user_image', + 'type', + 'email', + ) + list_display_links = ('id', 'nickname') + list_filter = ('author', 'type',) + readonly_fields = [] + + def get_readonly_fields(self, request, obj=None): + return list(self.readonly_fields) + \ + [field.name for field in obj._meta.fields] + \ + [field.name for field in obj._meta.many_to_many] + + def has_add_permission(self, request): + return False + + def link_to_usermodel(self, obj): + if obj.author: + info = (obj.author._meta.app_label, obj.author._meta.model_name) + link = reverse('admin:%s_%s_change' % info, args=(obj.author.id,)) + return format_html( + u'%s' % + (link, obj.author.nickname if obj.author.nickname else obj.author.email)) + + def show_user_image(self, obj): + img = obj.picture + return format_html( + u'' % + (img)) + + link_to_usermodel.short_description = '用户' + show_user_image.short_description = '用户头像' + + +class OAuthConfigAdmin(admin.ModelAdmin): + list_display = ('type', 'appkey', 'appsecret', 'is_enable') + list_filter = ('type',) diff --git a/oauth/apps.py b/oauth/apps.py new file mode 100644 index 0000000..17fcea2 --- /dev/null +++ b/oauth/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class OauthConfig(AppConfig): + name = 'oauth' diff --git a/oauth/forms.py b/oauth/forms.py new file mode 100644 index 0000000..0e4ede3 --- /dev/null +++ b/oauth/forms.py @@ -0,0 +1,12 @@ +from django.contrib.auth.forms import forms +from django.forms import widgets + + +class RequireEmailForm(forms.Form): + email = forms.EmailField(label='电子邮箱', required=True) + oauthid = forms.IntegerField(widget=forms.HiddenInput, required=False) + + def __init__(self, *args, **kwargs): + super(RequireEmailForm, self).__init__(*args, **kwargs) + self.fields['email'].widget = widgets.EmailInput( + attrs={'placeholder': "email", "class": "form-control"}) diff --git a/oauth/migrations/0001_initial.py b/oauth/migrations/0001_initial.py new file mode 100644 index 0000000..3aa3e03 --- /dev/null +++ b/oauth/migrations/0001_initial.py @@ -0,0 +1,57 @@ +# Generated by Django 4.1.7 on 2023-03-07 09:53 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='OAuthConfig', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('type', models.CharField(choices=[('weibo', '微博'), ('google', '谷歌'), ('github', 'GitHub'), ('facebook', 'FaceBook'), ('qq', 'QQ')], default='a', max_length=10, verbose_name='类型')), + ('appkey', models.CharField(max_length=200, verbose_name='AppKey')), + ('appsecret', models.CharField(max_length=200, verbose_name='AppSecret')), + ('callback_url', models.CharField(default='http://www.baidu.com', max_length=200, verbose_name='回调地址')), + ('is_enable', models.BooleanField(default=True, verbose_name='是否显示')), + ('created_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='创建时间')), + ('last_mod_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='修改时间')), + ], + options={ + 'verbose_name': 'oauth配置', + 'verbose_name_plural': 'oauth配置', + 'ordering': ['-created_time'], + }, + ), + migrations.CreateModel( + name='OAuthUser', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('openid', models.CharField(max_length=50)), + ('nickname', models.CharField(max_length=50, verbose_name='昵称')), + ('token', models.CharField(blank=True, max_length=150, null=True)), + ('picture', models.CharField(blank=True, max_length=350, null=True)), + ('type', models.CharField(max_length=50)), + ('email', models.CharField(blank=True, max_length=50, null=True)), + ('metadata', models.TextField(blank=True, null=True)), + ('created_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='创建时间')), + ('last_mod_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='修改时间')), + ('author', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='用户')), + ], + options={ + 'verbose_name': 'oauth用户', + 'verbose_name_plural': 'oauth用户', + 'ordering': ['-created_time'], + }, + ), + ] diff --git a/oauth/migrations/0002_alter_oauthconfig_options_alter_oauthuser_options_and_more.py b/oauth/migrations/0002_alter_oauthconfig_options_alter_oauthuser_options_and_more.py new file mode 100644 index 0000000..d5cc70e --- /dev/null +++ b/oauth/migrations/0002_alter_oauthconfig_options_alter_oauthuser_options_and_more.py @@ -0,0 +1,86 @@ +# Generated by Django 4.2.5 on 2023-09-06 13:13 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('oauth', '0001_initial'), + ] + + operations = [ + migrations.AlterModelOptions( + name='oauthconfig', + options={'ordering': ['-creation_time'], 'verbose_name': 'oauth配置', 'verbose_name_plural': 'oauth配置'}, + ), + migrations.AlterModelOptions( + name='oauthuser', + options={'ordering': ['-creation_time'], 'verbose_name': 'oauth user', 'verbose_name_plural': 'oauth user'}, + ), + migrations.RemoveField( + model_name='oauthconfig', + name='created_time', + ), + migrations.RemoveField( + model_name='oauthconfig', + name='last_mod_time', + ), + migrations.RemoveField( + model_name='oauthuser', + name='created_time', + ), + migrations.RemoveField( + model_name='oauthuser', + name='last_mod_time', + ), + migrations.AddField( + model_name='oauthconfig', + name='creation_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='creation time'), + ), + migrations.AddField( + model_name='oauthconfig', + name='last_modify_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='last modify time'), + ), + migrations.AddField( + model_name='oauthuser', + name='creation_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='creation time'), + ), + migrations.AddField( + model_name='oauthuser', + name='last_modify_time', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='last modify time'), + ), + migrations.AlterField( + model_name='oauthconfig', + name='callback_url', + field=models.CharField(default='', max_length=200, verbose_name='callback url'), + ), + migrations.AlterField( + model_name='oauthconfig', + name='is_enable', + field=models.BooleanField(default=True, verbose_name='is enable'), + ), + migrations.AlterField( + model_name='oauthconfig', + name='type', + field=models.CharField(choices=[('weibo', 'weibo'), ('google', 'google'), ('github', 'GitHub'), ('facebook', 'FaceBook'), ('qq', 'QQ')], default='a', max_length=10, verbose_name='type'), + ), + migrations.AlterField( + model_name='oauthuser', + name='author', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='author'), + ), + migrations.AlterField( + model_name='oauthuser', + name='nickname', + field=models.CharField(max_length=50, verbose_name='nickname'), + ), + ] diff --git a/oauth/migrations/0003_alter_oauthuser_nickname.py b/oauth/migrations/0003_alter_oauthuser_nickname.py new file mode 100644 index 0000000..6af08eb --- /dev/null +++ b/oauth/migrations/0003_alter_oauthuser_nickname.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.7 on 2024-01-26 02:41 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('oauth', '0002_alter_oauthconfig_options_alter_oauthuser_options_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='oauthuser', + name='nickname', + field=models.CharField(max_length=50, verbose_name='nick name'), + ), + ] diff --git a/oauth/migrations/__init__.py b/oauth/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/oauth/models.py b/oauth/models.py new file mode 100644 index 0000000..be838ed --- /dev/null +++ b/oauth/models.py @@ -0,0 +1,67 @@ +# Create your models here. +from django.conf import settings +from django.core.exceptions import ValidationError +from django.db import models +from django.utils.timezone import now +from django.utils.translation import gettext_lazy as _ + + +class OAuthUser(models.Model): + author = models.ForeignKey( + settings.AUTH_USER_MODEL, + verbose_name=_('author'), + blank=True, + null=True, + on_delete=models.CASCADE) + openid = models.CharField(max_length=50) + nickname = models.CharField(max_length=50, verbose_name=_('nick name')) + token = models.CharField(max_length=150, null=True, blank=True) + picture = models.CharField(max_length=350, blank=True, null=True) + type = models.CharField(blank=False, null=False, max_length=50) + email = models.CharField(max_length=50, null=True, blank=True) + metadata = models.TextField(null=True, blank=True) + creation_time = models.DateTimeField(_('creation time'), default=now) + last_modify_time = models.DateTimeField(_('last modify time'), default=now) + + def __str__(self): + return self.nickname + + class Meta: + verbose_name = _('oauth user') + verbose_name_plural = verbose_name + ordering = ['-creation_time'] + + +class OAuthConfig(models.Model): + TYPE = ( + ('weibo', _('weibo')), + ('google', _('google')), + ('github', 'GitHub'), + ('facebook', 'FaceBook'), + ('qq', 'QQ'), + ) + type = models.CharField(_('type'), max_length=10, choices=TYPE, default='a') + appkey = models.CharField(max_length=200, verbose_name='AppKey') + appsecret = models.CharField(max_length=200, verbose_name='AppSecret') + callback_url = models.CharField( + max_length=200, + verbose_name=_('callback url'), + blank=False, + default='') + is_enable = models.BooleanField( + _('is enable'), default=True, blank=False, null=False) + creation_time = models.DateTimeField(_('creation time'), default=now) + last_modify_time = models.DateTimeField(_('last modify time'), default=now) + + def clean(self): + if OAuthConfig.objects.filter( + type=self.type).exclude(id=self.id).count(): + raise ValidationError(_(self.type + _('already exists'))) + + def __str__(self): + return self.type + + class Meta: + verbose_name = 'oauth配置' + verbose_name_plural = verbose_name + ordering = ['-creation_time'] diff --git a/oauth/oauthmanager.py b/oauth/oauthmanager.py new file mode 100644 index 0000000..2e7ceef --- /dev/null +++ b/oauth/oauthmanager.py @@ -0,0 +1,504 @@ +import json +import logging +import os +import urllib.parse +from abc import ABCMeta, abstractmethod + +import requests + +from djangoblog.utils import cache_decorator +from oauth.models import OAuthUser, OAuthConfig + +logger = logging.getLogger(__name__) + + +class OAuthAccessTokenException(Exception): + ''' + oauth授权失败异常 + ''' + + +class BaseOauthManager(metaclass=ABCMeta): + """获取用户授权""" + AUTH_URL = None + """获取token""" + TOKEN_URL = None + """获取用户信息""" + API_URL = None + '''icon图标名''' + ICON_NAME = None + + def __init__(self, access_token=None, openid=None): + self.access_token = access_token + self.openid = openid + + @property + def is_access_token_set(self): + return self.access_token is not None + + @property + def is_authorized(self): + return self.is_access_token_set and self.access_token is not None and self.openid is not None + + @abstractmethod + def get_authorization_url(self, nexturl='/'): + pass + + @abstractmethod + def get_access_token_by_code(self, code): + pass + + @abstractmethod + def get_oauth_userinfo(self): + pass + + @abstractmethod + def get_picture(self, metadata): + pass + + def do_get(self, url, params, headers=None): + rsp = requests.get(url=url, params=params, headers=headers) + logger.info(rsp.text) + return rsp.text + + def do_post(self, url, params, headers=None): + rsp = requests.post(url, params, headers=headers) + logger.info(rsp.text) + return rsp.text + + def get_config(self): + value = OAuthConfig.objects.filter(type=self.ICON_NAME) + return value[0] if value else None + + +class WBOauthManager(BaseOauthManager): + AUTH_URL = 'https://api.weibo.com/oauth2/authorize' + TOKEN_URL = 'https://api.weibo.com/oauth2/access_token' + API_URL = 'https://api.weibo.com/2/users/show.json' + ICON_NAME = 'weibo' + + def __init__(self, access_token=None, openid=None): + config = self.get_config() + self.client_id = config.appkey if config else '' + self.client_secret = config.appsecret if config else '' + self.callback_url = config.callback_url if config else '' + super( + WBOauthManager, + self).__init__( + access_token=access_token, + openid=openid) + + def get_authorization_url(self, nexturl='/'): + params = { + 'client_id': self.client_id, + 'response_type': 'code', + 'redirect_uri': self.callback_url + '&next_url=' + nexturl + } + url = self.AUTH_URL + "?" + urllib.parse.urlencode(params) + return url + + def get_access_token_by_code(self, code): + + params = { + 'client_id': self.client_id, + 'client_secret': self.client_secret, + 'grant_type': 'authorization_code', + 'code': code, + 'redirect_uri': self.callback_url + } + rsp = self.do_post(self.TOKEN_URL, params) + + obj = json.loads(rsp) + if 'access_token' in obj: + self.access_token = str(obj['access_token']) + self.openid = str(obj['uid']) + return self.get_oauth_userinfo() + else: + raise OAuthAccessTokenException(rsp) + + def get_oauth_userinfo(self): + if not self.is_authorized: + return None + params = { + 'uid': self.openid, + 'access_token': self.access_token + } + rsp = self.do_get(self.API_URL, params) + try: + datas = json.loads(rsp) + user = OAuthUser() + user.metadata = rsp + user.picture = datas['avatar_large'] + user.nickname = datas['screen_name'] + user.openid = datas['id'] + user.type = 'weibo' + user.token = self.access_token + if 'email' in datas and datas['email']: + user.email = datas['email'] + return user + except Exception as e: + logger.error(e) + logger.error('weibo oauth error.rsp:' + rsp) + return None + + def get_picture(self, metadata): + datas = json.loads(metadata) + return datas['avatar_large'] + + +class ProxyManagerMixin: + def __init__(self, *args, **kwargs): + if os.environ.get("HTTP_PROXY"): + self.proxies = { + "http": os.environ.get("HTTP_PROXY"), + "https": os.environ.get("HTTP_PROXY") + } + else: + self.proxies = None + + def do_get(self, url, params, headers=None): + rsp = requests.get(url=url, params=params, headers=headers, proxies=self.proxies) + logger.info(rsp.text) + return rsp.text + + def do_post(self, url, params, headers=None): + rsp = requests.post(url, params, headers=headers, proxies=self.proxies) + logger.info(rsp.text) + return rsp.text + + +class GoogleOauthManager(ProxyManagerMixin, BaseOauthManager): + AUTH_URL = 'https://accounts.google.com/o/oauth2/v2/auth' + TOKEN_URL = 'https://www.googleapis.com/oauth2/v4/token' + API_URL = 'https://www.googleapis.com/oauth2/v3/userinfo' + ICON_NAME = 'google' + + def __init__(self, access_token=None, openid=None): + config = self.get_config() + self.client_id = config.appkey if config else '' + self.client_secret = config.appsecret if config else '' + self.callback_url = config.callback_url if config else '' + super( + GoogleOauthManager, + self).__init__( + access_token=access_token, + openid=openid) + + def get_authorization_url(self, nexturl='/'): + params = { + 'client_id': self.client_id, + 'response_type': 'code', + 'redirect_uri': self.callback_url, + 'scope': 'openid email', + } + url = self.AUTH_URL + "?" + urllib.parse.urlencode(params) + return url + + def get_access_token_by_code(self, code): + params = { + 'client_id': self.client_id, + 'client_secret': self.client_secret, + 'grant_type': 'authorization_code', + 'code': code, + + 'redirect_uri': self.callback_url + } + rsp = self.do_post(self.TOKEN_URL, params) + + obj = json.loads(rsp) + + if 'access_token' in obj: + self.access_token = str(obj['access_token']) + self.openid = str(obj['id_token']) + logger.info(self.ICON_NAME + ' oauth ' + rsp) + return self.access_token + else: + raise OAuthAccessTokenException(rsp) + + def get_oauth_userinfo(self): + if not self.is_authorized: + return None + params = { + 'access_token': self.access_token + } + rsp = self.do_get(self.API_URL, params) + try: + + datas = json.loads(rsp) + user = OAuthUser() + user.metadata = rsp + user.picture = datas['picture'] + user.nickname = datas['name'] + user.openid = datas['sub'] + user.token = self.access_token + user.type = 'google' + if datas['email']: + user.email = datas['email'] + return user + except Exception as e: + logger.error(e) + logger.error('google oauth error.rsp:' + rsp) + return None + + def get_picture(self, metadata): + datas = json.loads(metadata) + return datas['picture'] + + +class GitHubOauthManager(ProxyManagerMixin, BaseOauthManager): + AUTH_URL = 'https://github.com/login/oauth/authorize' + TOKEN_URL = 'https://github.com/login/oauth/access_token' + API_URL = 'https://api.github.com/user' + ICON_NAME = 'github' + + def __init__(self, access_token=None, openid=None): + config = self.get_config() + self.client_id = config.appkey if config else '' + self.client_secret = config.appsecret if config else '' + self.callback_url = config.callback_url if config else '' + super( + GitHubOauthManager, + self).__init__( + access_token=access_token, + openid=openid) + + def get_authorization_url(self, next_url='/'): + params = { + 'client_id': self.client_id, + 'response_type': 'code', + 'redirect_uri': f'{self.callback_url}&next_url={next_url}', + 'scope': 'user' + } + url = self.AUTH_URL + "?" + urllib.parse.urlencode(params) + return url + + def get_access_token_by_code(self, code): + params = { + 'client_id': self.client_id, + 'client_secret': self.client_secret, + 'grant_type': 'authorization_code', + 'code': code, + + 'redirect_uri': self.callback_url + } + rsp = self.do_post(self.TOKEN_URL, params) + + from urllib import parse + r = parse.parse_qs(rsp) + if 'access_token' in r: + self.access_token = (r['access_token'][0]) + return self.access_token + else: + raise OAuthAccessTokenException(rsp) + + def get_oauth_userinfo(self): + + rsp = self.do_get(self.API_URL, params={}, headers={ + "Authorization": "token " + self.access_token + }) + try: + datas = json.loads(rsp) + user = OAuthUser() + user.picture = datas['avatar_url'] + user.nickname = datas['name'] + user.openid = datas['id'] + user.type = 'github' + user.token = self.access_token + user.metadata = rsp + if 'email' in datas and datas['email']: + user.email = datas['email'] + return user + except Exception as e: + logger.error(e) + logger.error('github oauth error.rsp:' + rsp) + return None + + def get_picture(self, metadata): + datas = json.loads(metadata) + return datas['avatar_url'] + + +class FaceBookOauthManager(ProxyManagerMixin, BaseOauthManager): + AUTH_URL = 'https://www.facebook.com/v16.0/dialog/oauth' + TOKEN_URL = 'https://graph.facebook.com/v16.0/oauth/access_token' + API_URL = 'https://graph.facebook.com/me' + ICON_NAME = 'facebook' + + def __init__(self, access_token=None, openid=None): + config = self.get_config() + self.client_id = config.appkey if config else '' + self.client_secret = config.appsecret if config else '' + self.callback_url = config.callback_url if config else '' + super( + FaceBookOauthManager, + self).__init__( + access_token=access_token, + openid=openid) + + def get_authorization_url(self, next_url='/'): + params = { + 'client_id': self.client_id, + 'response_type': 'code', + 'redirect_uri': self.callback_url, + 'scope': 'email,public_profile' + } + url = self.AUTH_URL + "?" + urllib.parse.urlencode(params) + return url + + def get_access_token_by_code(self, code): + params = { + 'client_id': self.client_id, + 'client_secret': self.client_secret, + # 'grant_type': 'authorization_code', + 'code': code, + + 'redirect_uri': self.callback_url + } + rsp = self.do_post(self.TOKEN_URL, params) + + obj = json.loads(rsp) + if 'access_token' in obj: + token = str(obj['access_token']) + self.access_token = token + return self.access_token + else: + raise OAuthAccessTokenException(rsp) + + def get_oauth_userinfo(self): + params = { + 'access_token': self.access_token, + 'fields': 'id,name,picture,email' + } + try: + rsp = self.do_get(self.API_URL, params) + datas = json.loads(rsp) + user = OAuthUser() + user.nickname = datas['name'] + user.openid = datas['id'] + user.type = 'facebook' + user.token = self.access_token + user.metadata = rsp + if 'email' in datas and datas['email']: + user.email = datas['email'] + if 'picture' in datas and datas['picture'] and datas['picture']['data'] and datas['picture']['data']['url']: + user.picture = str(datas['picture']['data']['url']) + return user + except Exception as e: + logger.error(e) + return None + + def get_picture(self, metadata): + datas = json.loads(metadata) + return str(datas['picture']['data']['url']) + + +class QQOauthManager(BaseOauthManager): + AUTH_URL = 'https://graph.qq.com/oauth2.0/authorize' + TOKEN_URL = 'https://graph.qq.com/oauth2.0/token' + API_URL = 'https://graph.qq.com/user/get_user_info' + OPEN_ID_URL = 'https://graph.qq.com/oauth2.0/me' + ICON_NAME = 'qq' + + def __init__(self, access_token=None, openid=None): + config = self.get_config() + self.client_id = config.appkey if config else '' + self.client_secret = config.appsecret if config else '' + self.callback_url = config.callback_url if config else '' + super( + QQOauthManager, + self).__init__( + access_token=access_token, + openid=openid) + + def get_authorization_url(self, next_url='/'): + params = { + 'response_type': 'code', + 'client_id': self.client_id, + 'redirect_uri': self.callback_url + '&next_url=' + next_url, + } + url = self.AUTH_URL + "?" + urllib.parse.urlencode(params) + return url + + def get_access_token_by_code(self, code): + params = { + 'grant_type': 'authorization_code', + 'client_id': self.client_id, + 'client_secret': self.client_secret, + 'code': code, + 'redirect_uri': self.callback_url + } + rsp = self.do_get(self.TOKEN_URL, params) + if rsp: + d = urllib.parse.parse_qs(rsp) + if 'access_token' in d: + token = d['access_token'] + self.access_token = token[0] + return token + else: + raise OAuthAccessTokenException(rsp) + + def get_open_id(self): + if self.is_access_token_set: + params = { + 'access_token': self.access_token + } + rsp = self.do_get(self.OPEN_ID_URL, params) + if rsp: + rsp = rsp.replace( + 'callback(', '').replace( + ')', '').replace( + ';', '') + obj = json.loads(rsp) + openid = str(obj['openid']) + self.openid = openid + return openid + + def get_oauth_userinfo(self): + openid = self.get_open_id() + if openid: + params = { + 'access_token': self.access_token, + 'oauth_consumer_key': self.client_id, + 'openid': self.openid + } + rsp = self.do_get(self.API_URL, params) + logger.info(rsp) + obj = json.loads(rsp) + user = OAuthUser() + user.nickname = obj['nickname'] + user.openid = openid + user.type = 'qq' + user.token = self.access_token + user.metadata = rsp + if 'email' in obj: + user.email = obj['email'] + if 'figureurl' in obj: + user.picture = str(obj['figureurl']) + return user + + def get_picture(self, metadata): + datas = json.loads(metadata) + return str(datas['figureurl']) + + +@cache_decorator(expiration=100 * 60) +def get_oauth_apps(): + configs = OAuthConfig.objects.filter(is_enable=True).all() + if not configs: + return [] + configtypes = [x.type for x in configs] + applications = BaseOauthManager.__subclasses__() + apps = [x() for x in applications if x().ICON_NAME.lower() in configtypes] + return apps + + +def get_manager_by_type(type): + applications = get_oauth_apps() + if applications: + finds = list( + filter( + lambda x: x.ICON_NAME.lower() == type.lower(), + applications)) + if finds: + return finds[0] + return None diff --git a/oauth/templatetags/__init__.py b/oauth/templatetags/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/oauth/templatetags/__init__.py @@ -0,0 +1 @@ + diff --git a/oauth/templatetags/oauth_tags.py b/oauth/templatetags/oauth_tags.py new file mode 100644 index 0000000..7b687d5 --- /dev/null +++ b/oauth/templatetags/oauth_tags.py @@ -0,0 +1,22 @@ +from django import template +from django.urls import reverse + +from oauth.oauthmanager import get_oauth_apps + +register = template.Library() + + +@register.inclusion_tag('oauth/oauth_applications.html') +def load_oauth_applications(request): + applications = get_oauth_apps() + if applications: + baseurl = reverse('oauth:oauthlogin') + path = request.get_full_path() + + apps = list(map(lambda x: (x.ICON_NAME, '{baseurl}?type={type}&next_url={next}'.format( + baseurl=baseurl, type=x.ICON_NAME, next=path)), applications)) + else: + apps = [] + return { + 'apps': apps + } diff --git a/oauth/tests.py b/oauth/tests.py new file mode 100644 index 0000000..bb23b9b --- /dev/null +++ b/oauth/tests.py @@ -0,0 +1,249 @@ +import json +from unittest.mock import patch + +from django.conf import settings +from django.contrib import auth +from django.test import Client, RequestFactory, TestCase +from django.urls import reverse + +from djangoblog.utils import get_sha256 +from oauth.models import OAuthConfig +from oauth.oauthmanager import BaseOauthManager + + +# Create your tests here. +class OAuthConfigTest(TestCase): + def setUp(self): + self.client = Client() + self.factory = RequestFactory() + + def test_oauth_login_test(self): + c = OAuthConfig() + c.type = 'weibo' + c.appkey = 'appkey' + c.appsecret = 'appsecret' + c.save() + + 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, '/') + + +class OauthLoginTest(TestCase): + def setUp(self) -> None: + self.client = Client() + self.factory = RequestFactory() + self.apps = self.init_apps() + + def init_apps(self): + applications = [p() for p in BaseOauthManager.__subclasses__()] + for application in applications: + c = OAuthConfig() + c.type = application.ICON_NAME.lower() + c.appkey = 'appkey' + c.appsecret = 'appsecret' + c.save() + return applications + + def get_app_by_type(self, type): + for app in self.apps: + if app.ICON_NAME.lower() == type: + return app + + @patch("oauth.oauthmanager.WBOauthManager.do_post") + @patch("oauth.oauthmanager.WBOauthManager.do_get") + def test_weibo_login(self, mock_do_get, mock_do_post): + weibo_app = self.get_app_by_type('weibo') + assert weibo_app + url = weibo_app.get_authorization_url() + mock_do_post.return_value = json.dumps({"access_token": "access_token", + "uid": "uid" + }) + mock_do_get.return_value = json.dumps({ + "avatar_large": "avatar_large", + "screen_name": "screen_name", + "id": "id", + "email": "email", + }) + 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_app = self.get_app_by_type('google') + assert google_app + url = google_app.get_authorization_url() + mock_do_post.return_value = json.dumps({ + "access_token": "access_token", + "id_token": "id_token", + }) + mock_do_get.return_value = json.dumps({ + "picture": "picture", + "name": "name", + "sub": "sub", + "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') + + @patch("oauth.oauthmanager.GitHubOauthManager.do_post") + @patch("oauth.oauthmanager.GitHubOauthManager.do_get") + def test_github_login(self, mock_do_get, mock_do_post): + github_app = self.get_app_by_type('github') + assert github_app + url = github_app.get_authorization_url() + self.assertTrue("github.com" in url) + self.assertTrue("client_id" in url) + mock_do_post.return_value = "access_token=gho_16C7e42F292c6912E7710c838347Ae178B4a&scope=repo%2Cgist&token_type=bearer" + 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_app = self.get_app_by_type('facebook') + assert facebook_app + url = facebook_app.get_authorization_url() + self.assertTrue("facebook.com" in url) + mock_do_post.return_value = json.dumps({ + "access_token": "access_token", + }) + mock_do_get.return_value = json.dumps({ + "name": "name", + "id": "id", + "email": "email", + "picture": { + "data": { + "url": "url" + } + } + }) + 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({ + "nickname": "nickname", + "email": "email", + "figureurl": "figureurl", + "openid": "openid", + }) + ]) + def test_qq_login(self, mock_do_get): + qq_app = self.get_app_by_type('qq') + assert qq_app + url = qq_app.get_authorization_url() + self.assertTrue("qq.com" in 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): + + mock_do_post.return_value = json.dumps({"access_token": "access_token", + "uid": "uid" + }) + mock_user_info = { + "avatar_large": "avatar_large", + "screen_name": "screen_name1", + "id": "id", + "email": "email", + } + 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) + self.assertEqual(user.username, mock_user_info['screen_name']) + self.assertEqual(user.email, mock_user_info['email']) + + @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): + + mock_do_post.return_value = json.dumps({"access_token": "access_token", + "uid": "uid" + }) + mock_user_info = { + "avatar_large": "avatar_large", + "screen_name": "screen_name1", + "id": "id", + } + 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_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 = 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 + }) + 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) diff --git a/oauth/urls.py b/oauth/urls.py new file mode 100644 index 0000000..c4a12a0 --- /dev/null +++ b/oauth/urls.py @@ -0,0 +1,25 @@ +from django.urls import path + +from . import views + +app_name = "oauth" +urlpatterns = [ + path( + r'oauth/authorize', + views.authorize), + path( + r'oauth/requireemail/.html', + views.RequireEmailView.as_view(), + name='require_email'), + path( + r'oauth/emailconfirm//.html', + views.emailconfirm, + name='email_confirm'), + path( + r'oauth/bindsuccess/.html', + views.bindsuccess, + name='bindsuccess'), + path( + r'oauth/oauthlogin', + views.oauthlogin, + name='oauthlogin')] diff --git a/oauth/views.py b/oauth/views.py new file mode 100644 index 0000000..12e3a6e --- /dev/null +++ b/oauth/views.py @@ -0,0 +1,253 @@ +import logging +# Create your views here. +from urllib.parse import urlparse + +from django.conf import settings +from django.contrib.auth import get_user_model +from django.contrib.auth import login +from django.core.exceptions import ObjectDoesNotExist +from django.db import transaction +from django.http import HttpResponseForbidden +from django.http import HttpResponseRedirect +from django.shortcuts import get_object_or_404 +from django.shortcuts import render +from django.urls import reverse +from django.utils import timezone +from django.utils.translation import gettext_lazy as _ +from django.views.generic import FormView + +from djangoblog.blog_signals import oauth_user_login_signal +from djangoblog.utils import get_current_site +from djangoblog.utils import send_email, get_sha256 +from oauth.forms import RequireEmailForm +from .models import OAuthUser +from .oauthmanager import get_manager_by_type, OAuthAccessTokenException + +logger = logging.getLogger(__name__) + + +def get_redirecturl(request): + nexturl = request.GET.get('next_url', None) + if not nexturl or nexturl == '/login/' or nexturl == '/login': + nexturl = '/' + return nexturl + p = urlparse(nexturl) + if p.netloc: + site = get_current_site().domain + if not p.netloc.replace('www.', '') == site.replace('www.', ''): + logger.info('非法url:' + nexturl) + return "/" + return nexturl + + +def oauthlogin(request): + type = request.GET.get('type', None) + if not type: + return HttpResponseRedirect('/') + manager = get_manager_by_type(type) + if not manager: + return HttpResponseRedirect('/') + nexturl = get_redirecturl(request) + authorizeurl = manager.get_authorization_url(nexturl) + return HttpResponseRedirect(authorizeurl) + + +def authorize(request): + type = request.GET.get('type', None) + if not type: + return HttpResponseRedirect('/') + manager = get_manager_by_type(type) + if not manager: + return HttpResponseRedirect('/') + code = request.GET.get('code', None) + try: + rsp = manager.get_access_token_by_code(code) + except OAuthAccessTokenException as e: + logger.warning("OAuthAccessTokenException:" + str(e)) + return HttpResponseRedirect('/') + except Exception as e: + logger.error(e) + rsp = None + nexturl = get_redirecturl(request) + if not rsp: + return HttpResponseRedirect(manager.get_authorization_url(nexturl)) + user = manager.get_oauth_userinfo() + if user: + if not user.nickname or not user.nickname.strip(): + user.nickname = "djangoblog" + timezone.now().strftime('%y%m%d%I%M%S') + try: + temp = OAuthUser.objects.get(type=type, openid=user.openid) + temp.picture = user.picture + temp.metadata = user.metadata + temp.nickname = user.nickname + user = temp + except ObjectDoesNotExist: + pass + # facebook的token过长 + if type == 'facebook': + user.token = '' + if user.email: + with transaction.atomic(): + author = None + try: + author = get_user_model().objects.get(id=user.author_id) + except ObjectDoesNotExist: + pass + if not author: + result = get_user_model().objects.get_or_create(email=user.email) + author = result[0] + if result[1]: + try: + get_user_model().objects.get(username=user.nickname) + except ObjectDoesNotExist: + author.username = user.nickname + else: + author.username = "djangoblog" + timezone.now().strftime('%y%m%d%I%M%S') + author.source = 'authorize' + author.save() + + user.author = author + user.save() + + oauth_user_login_signal.send( + sender=authorize.__class__, id=user.id) + login(request, author) + return HttpResponseRedirect(nexturl) + else: + user.save() + url = reverse('oauth:require_email', kwargs={ + 'oauthid': user.id + }) + + return HttpResponseRedirect(url) + else: + return HttpResponseRedirect(nexturl) + + +def emailconfirm(request, id, sign): + if not sign: + return HttpResponseForbidden() + if not get_sha256(settings.SECRET_KEY + + str(id) + + settings.SECRET_KEY).upper() == sign.upper(): + return HttpResponseForbidden() + oauthuser = get_object_or_404(OAuthUser, pk=id) + with transaction.atomic(): + if oauthuser.author: + author = get_user_model().objects.get(pk=oauthuser.author_id) + else: + result = get_user_model().objects.get_or_create(email=oauthuser.email) + author = result[0] + if result[1]: + author.source = 'emailconfirm' + author.username = oauthuser.nickname.strip() if oauthuser.nickname.strip( + ) else "djangoblog" + timezone.now().strftime('%y%m%d%I%M%S') + author.save() + oauthuser.author = author + oauthuser.save() + oauth_user_login_signal.send( + sender=emailconfirm.__class__, + id=oauthuser.id) + login(request, author) + + site = 'http://' + get_current_site().domain + content = _(''' +

Congratulations, you have successfully bound your email address. You can use + %(oauthuser_type)s to directly log in to this website without a password.

+ You are welcome to continue to follow this site, the address is + %(site)s + Thank you again! +
+ If the link above cannot be opened, please copy this link to your browser. + %(site)s + ''') % {'oauthuser_type': oauthuser.type, 'site': site} + + send_email(emailto=[oauthuser.email, ], title=_('Congratulations on your successful binding!'), content=content) + url = reverse('oauth:bindsuccess', kwargs={ + 'oauthid': id + }) + url = url + '?type=success' + return HttpResponseRedirect(url) + + +class RequireEmailView(FormView): + form_class = RequireEmailForm + template_name = 'oauth/require_email.html' + + def get(self, request, *args, **kwargs): + oauthid = self.kwargs['oauthid'] + oauthuser = get_object_or_404(OAuthUser, pk=oauthid) + if oauthuser.email: + pass + # return HttpResponseRedirect('/') + + return super(RequireEmailView, self).get(request, *args, **kwargs) + + def get_initial(self): + oauthid = self.kwargs['oauthid'] + return { + 'email': '', + 'oauthid': oauthid + } + + def get_context_data(self, **kwargs): + oauthid = self.kwargs['oauthid'] + oauthuser = get_object_or_404(OAuthUser, pk=oauthid) + if oauthuser.picture: + kwargs['picture'] = oauthuser.picture + return super(RequireEmailView, self).get_context_data(**kwargs) + + def form_valid(self, form): + email = form.cleaned_data['email'] + oauthid = form.cleaned_data['oauthid'] + oauthuser = get_object_or_404(OAuthUser, pk=oauthid) + oauthuser.email = email + oauthuser.save() + sign = get_sha256(settings.SECRET_KEY + + str(oauthuser.id) + settings.SECRET_KEY) + site = get_current_site().domain + if settings.DEBUG: + site = '127.0.0.1:8000' + path = reverse('oauth:email_confirm', kwargs={ + 'id': oauthid, + 'sign': sign + }) + url = "http://{site}{path}".format(site=site, path=path) + + content = _(""" +

Please click the link below to bind your email

+ + %(url)s + + Thank you again! +
+ If the link above cannot be opened, please copy this link to your browser. +
+ %(url)s + """) % {'url': url} + send_email(emailto=[email, ], title=_('Bind your email'), content=content) + url = reverse('oauth:bindsuccess', kwargs={ + 'oauthid': oauthid + }) + url = url + '?type=email' + return HttpResponseRedirect(url) + + +def bindsuccess(request, oauthid): + type = request.GET.get('type', None) + oauthuser = get_object_or_404(OAuthUser, pk=oauthid) + if type == 'email': + title = _('Bind your email') + content = _( + 'Congratulations, the binding is just one step away. ' + 'Please log in to your email to check the email to complete the binding. Thank you.') + else: + title = _('Binding successful') + content = _( + "Congratulations, you have successfully bound your email address. You can use %(oauthuser_type)s" + " to directly log in to this website without a password. You are welcome to continue to follow this site." % { + 'oauthuser_type': oauthuser.type}) + return render(request, 'oauth/bindsuccess.html', { + 'title': title, + 'content': content + }) diff --git a/owntracks/__init__.py b/owntracks/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/owntracks/admin.py b/owntracks/admin.py new file mode 100644 index 0000000..655b535 --- /dev/null +++ b/owntracks/admin.py @@ -0,0 +1,7 @@ +from django.contrib import admin + +# Register your models here. + + +class OwnTrackLogsAdmin(admin.ModelAdmin): + pass diff --git a/owntracks/apps.py b/owntracks/apps.py new file mode 100644 index 0000000..1bc5f12 --- /dev/null +++ b/owntracks/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class OwntracksConfig(AppConfig): + name = 'owntracks' diff --git a/owntracks/migrations/0001_initial.py b/owntracks/migrations/0001_initial.py new file mode 100644 index 0000000..9eee55c --- /dev/null +++ b/owntracks/migrations/0001_initial.py @@ -0,0 +1,31 @@ +# Generated by Django 4.1.7 on 2023-03-02 07:14 + +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='OwnTrackLog', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('tid', models.CharField(max_length=100, verbose_name='用户')), + ('lat', models.FloatField(verbose_name='纬度')), + ('lon', models.FloatField(verbose_name='经度')), + ('created_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='创建时间')), + ], + options={ + 'verbose_name': 'OwnTrackLogs', + 'verbose_name_plural': 'OwnTrackLogs', + 'ordering': ['created_time'], + 'get_latest_by': 'created_time', + }, + ), + ] diff --git a/owntracks/migrations/0002_alter_owntracklog_options_and_more.py b/owntracks/migrations/0002_alter_owntracklog_options_and_more.py new file mode 100644 index 0000000..b4f8dec --- /dev/null +++ b/owntracks/migrations/0002_alter_owntracklog_options_and_more.py @@ -0,0 +1,22 @@ +# Generated by Django 4.2.5 on 2023-09-06 13:19 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('owntracks', '0001_initial'), + ] + + operations = [ + migrations.AlterModelOptions( + name='owntracklog', + options={'get_latest_by': 'creation_time', 'ordering': ['creation_time'], 'verbose_name': 'OwnTrackLogs', 'verbose_name_plural': 'OwnTrackLogs'}, + ), + migrations.RenameField( + model_name='owntracklog', + old_name='created_time', + new_name='creation_time', + ), + ] diff --git a/owntracks/migrations/__init__.py b/owntracks/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/owntracks/models.py b/owntracks/models.py new file mode 100644 index 0000000..760942c --- /dev/null +++ b/owntracks/models.py @@ -0,0 +1,20 @@ +from django.db import models +from django.utils.timezone import now + + +# Create your models here. + +class OwnTrackLog(models.Model): + tid = models.CharField(max_length=100, null=False, verbose_name='用户') + lat = models.FloatField(verbose_name='纬度') + lon = models.FloatField(verbose_name='经度') + creation_time = models.DateTimeField('创建时间', default=now) + + def __str__(self): + return self.tid + + class Meta: + ordering = ['creation_time'] + verbose_name = "OwnTrackLogs" + verbose_name_plural = verbose_name + get_latest_by = 'creation_time' diff --git a/owntracks/tests.py b/owntracks/tests.py new file mode 100644 index 0000000..3b4b9d8 --- /dev/null +++ b/owntracks/tests.py @@ -0,0 +1,64 @@ +import json + +from django.test import Client, RequestFactory, TestCase + +from accounts.models import BlogUser +from .models import OwnTrackLog + + +# Create your tests here. + +class OwnTrackLogTest(TestCase): + def setUp(self): + self.client = Client() + self.factory = RequestFactory() + + def test_own_track_log(self): + o = { + 'tid': 12, + 'lat': 123.123, + 'lon': 134.341 + } + + self.client.post( + '/owntracks/logtracks', + json.dumps(o), + content_type='application/json') + length = len(OwnTrackLog.objects.all()) + self.assertEqual(length, 1) + + o = { + 'tid': 12, + 'lat': 123.123 + } + + self.client.post( + '/owntracks/logtracks', + json.dumps(o), + content_type='application/json') + length = len(OwnTrackLog.objects.all()) + self.assertEqual(length, 1) + + rsp = self.client.get('/owntracks/show_maps') + self.assertEqual(rsp.status_code, 302) + + user = BlogUser.objects.create_superuser( + email="liangliangyy1@gmail.com", + username="liangliangyy1", + password="liangliangyy1") + + self.client.login(username='liangliangyy1', password='liangliangyy1') + s = OwnTrackLog() + s.tid = 12 + s.lon = 123.234 + s.lat = 34.234 + s.save() + + rsp = self.client.get('/owntracks/show_dates') + self.assertEqual(rsp.status_code, 200) + rsp = self.client.get('/owntracks/show_maps') + self.assertEqual(rsp.status_code, 200) + rsp = self.client.get('/owntracks/get_datas') + self.assertEqual(rsp.status_code, 200) + rsp = self.client.get('/owntracks/get_datas?date=2018-02-26') + self.assertEqual(rsp.status_code, 200) diff --git a/owntracks/urls.py b/owntracks/urls.py new file mode 100644 index 0000000..c19ada8 --- /dev/null +++ b/owntracks/urls.py @@ -0,0 +1,12 @@ +from django.urls import path + +from . import views + +app_name = "owntracks" + +urlpatterns = [ + path('owntracks/logtracks', views.manage_owntrack_log, name='logtracks'), + path('owntracks/show_maps', views.show_maps, name='show_maps'), + path('owntracks/get_datas', views.get_datas, name='get_datas'), + path('owntracks/show_dates', views.show_log_dates, name='show_dates') +] diff --git a/owntracks/views.py b/owntracks/views.py new file mode 100644 index 0000000..4c72bdd --- /dev/null +++ b/owntracks/views.py @@ -0,0 +1,127 @@ +# Create your views here. +import datetime +import itertools +import json +import logging +from datetime import timezone +from itertools import groupby + +import django +import requests +from django.contrib.auth.decorators import login_required +from django.http import HttpResponse +from django.http import JsonResponse +from django.shortcuts import render +from django.views.decorators.csrf import csrf_exempt + +from .models import OwnTrackLog + +logger = logging.getLogger(__name__) + + +@csrf_exempt +def manage_owntrack_log(request): + try: + s = json.loads(request.read().decode('utf-8')) + tid = s['tid'] + lat = s['lat'] + lon = s['lon'] + + logger.info( + 'tid:{tid}.lat:{lat}.lon:{lon}'.format( + tid=tid, lat=lat, lon=lon)) + if tid and lat and lon: + m = OwnTrackLog() + m.tid = tid + m.lat = lat + m.lon = lon + m.save() + return HttpResponse('ok') + else: + return HttpResponse('data error') + except Exception as e: + logger.error(e) + return HttpResponse('error') + + +@login_required +def show_maps(request): + if request.user.is_superuser: + defaultdate = str(datetime.datetime.now(timezone.utc).date()) + date = request.GET.get('date', defaultdate) + context = { + 'date': date + } + return render(request, 'owntracks/show_maps.html', context) + else: + from django.http import HttpResponseForbidden + return HttpResponseForbidden() + + +@login_required +def show_log_dates(request): + dates = OwnTrackLog.objects.values_list('creation_time', flat=True) + results = list(sorted(set(map(lambda x: x.strftime('%Y-%m-%d'), dates)))) + + context = { + 'results': results + } + return render(request, 'owntracks/show_log_dates.html', context) + + +def convert_to_amap(locations): + convert_result = [] + it = iter(locations) + + item = list(itertools.islice(it, 30)) + while item: + datas = ';'.join( + set(map(lambda x: str(x.lon) + ',' + str(x.lat), item))) + + key = '8440a376dfc9743d8924bf0ad141f28e' + api = 'http://restapi.amap.com/v3/assistant/coordinate/convert' + query = { + 'key': key, + 'locations': datas, + 'coordsys': 'gps' + } + rsp = requests.get(url=api, params=query) + result = json.loads(rsp.text) + if "locations" in result: + convert_result.append(result['locations']) + item = list(itertools.islice(it, 30)) + + return ";".join(convert_result) + + +@login_required +def get_datas(request): + now = django.utils.timezone.now().replace(tzinfo=timezone.utc) + querydate = django.utils.timezone.datetime( + now.year, now.month, now.day, 0, 0, 0) + if request.GET.get('date', None): + date = list(map(lambda x: int(x), request.GET.get('date').split('-'))) + querydate = django.utils.timezone.datetime( + date[0], date[1], date[2], 0, 0, 0) + nextdate = querydate + datetime.timedelta(days=1) + models = OwnTrackLog.objects.filter( + creation_time__range=(querydate, nextdate)) + result = list() + if models and len(models): + for tid, item in groupby( + sorted(models, key=lambda k: k.tid), key=lambda k: k.tid): + + d = dict() + d["name"] = tid + paths = list() + # 使用高德转换后的经纬度 + # locations = convert_to_amap( + # sorted(item, key=lambda x: x.creation_time)) + # for i in locations.split(';'): + # paths.append(i.split(',')) + # 使用GPS原始经纬度 + for location in sorted(item, key=lambda x: x.creation_time): + paths.append([str(location.lon), str(location.lat)]) + d["path"] = paths + result.append(d) + return JsonResponse(result, safe=False) diff --git a/plugins/__init__.py b/plugins/__init__.py new file mode 100644 index 0000000..e88afca --- /dev/null +++ b/plugins/__init__.py @@ -0,0 +1 @@ +# This file makes this a Python package diff --git a/plugins/article_copyright/__init__.py b/plugins/article_copyright/__init__.py new file mode 100644 index 0000000..e88afca --- /dev/null +++ b/plugins/article_copyright/__init__.py @@ -0,0 +1 @@ +# This file makes this a Python package diff --git a/plugins/article_copyright/plugin.py b/plugins/article_copyright/plugin.py new file mode 100644 index 0000000..317fed2 --- /dev/null +++ b/plugins/article_copyright/plugin.py @@ -0,0 +1,32 @@ +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 + + +class ArticleCopyrightPlugin(BasePlugin): + PLUGIN_NAME = '文章结尾版权声明' + PLUGIN_DESCRIPTION = '一个在文章正文末尾添加版权声明的插件。' + PLUGIN_VERSION = '0.2.0' + PLUGIN_AUTHOR = 'liangliangyy' + + # 2. 实现 register_hooks 方法,专门用于注册钩子 + def register_hooks(self): + # 在这里将插件的方法注册到指定的钩子上 + hooks.register(ARTICLE_CONTENT_HOOK_NAME, self.add_copyright_to_content) + + def add_copyright_to_content(self, content, *args, **kwargs): + """ + 这个方法会被注册到 'the_content' 过滤器钩子上。 + 它接收原始内容,并返回添加了版权信息的新内容。 + """ + article = kwargs.get('article') + if not article: + return content + + copyright_info = f"\n

本文由 {article.author.username} 原创,转载请注明出处。

" + return content + copyright_info + + +# 3. 实例化插件。 +# 这会自动调用 BasePlugin.__init__,然后 BasePlugin.__init__ 会调用我们上面定义的 register_hooks 方法。 +plugin = ArticleCopyrightPlugin() diff --git a/plugins/external_links/__init__.py b/plugins/external_links/__init__.py new file mode 100644 index 0000000..e88afca --- /dev/null +++ b/plugins/external_links/__init__.py @@ -0,0 +1 @@ +# This file makes this a Python package diff --git a/plugins/external_links/plugin.py b/plugins/external_links/plugin.py new file mode 100644 index 0000000..5b2ef14 --- /dev/null +++ b/plugins/external_links/plugin.py @@ -0,0 +1,48 @@ +import re +from urllib.parse import urlparse +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 + + +class ExternalLinksPlugin(BasePlugin): + PLUGIN_NAME = '外部链接处理器' + PLUGIN_DESCRIPTION = '自动为文章中的外部链接添加 target="_blank" 和 rel="noopener noreferrer" 属性。' + PLUGIN_VERSION = '0.1.0' + PLUGIN_AUTHOR = 'liangliangyy' + + def register_hooks(self): + hooks.register(ARTICLE_CONTENT_HOOK_NAME, self.process_external_links) + + def process_external_links(self, content, *args, **kwargs): + from djangoblog.utils import get_current_site + site_domain = get_current_site().domain + + # 正则表达式查找所有 标签 + link_pattern = re.compile(r'(]*?\s+)?href=")([^"]*)(".*?/a>)', re.IGNORECASE) + + def replacer(match): + # match.group(1) 是 ... + href = match.group(2) + + # 如果链接已经有 target 属性,则不处理 + if 'target=' in match.group(0).lower(): + return match.group(0) + + # 解析链接 + parsed_url = urlparse(href) + + # 如果链接是外部的 (有域名且域名不等于当前网站域名) + if parsed_url.netloc and parsed_url.netloc != site_domain: + # 添加 target 和 rel 属性 + return f'{match.group(1)}{href}" target="_blank" rel="noopener noreferrer"{match.group(3)}' + + # 否则返回原样 + return match.group(0) + + return link_pattern.sub(replacer, content) + + +plugin = ExternalLinksPlugin() diff --git a/plugins/reading_time/__init__.py b/plugins/reading_time/__init__.py new file mode 100644 index 0000000..e88afca --- /dev/null +++ b/plugins/reading_time/__init__.py @@ -0,0 +1 @@ +# This file makes this a Python package diff --git a/plugins/reading_time/plugin.py b/plugins/reading_time/plugin.py new file mode 100644 index 0000000..35f9db1 --- /dev/null +++ b/plugins/reading_time/plugin.py @@ -0,0 +1,43 @@ +import math +import re +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 + + +class ReadingTimePlugin(BasePlugin): + PLUGIN_NAME = '阅读时间预测' + PLUGIN_DESCRIPTION = '估算文章阅读时间并显示在文章开头。' + PLUGIN_VERSION = '0.1.0' + PLUGIN_AUTHOR = 'liangliangyy' + + def register_hooks(self): + hooks.register(ARTICLE_CONTENT_HOOK_NAME, self.add_reading_time) + + def add_reading_time(self, content, *args, **kwargs): + """ + 计算阅读时间并添加到内容开头。 + """ + # 移除HTML标签和空白字符,以获得纯文本 + clean_content = re.sub(r'<[^>]*>', '', content) + clean_content = clean_content.strip() + + # 中文和英文单词混合计数的一个简单方法 + # 匹配中文字符或连续的非中文字符(视为单词) + words = re.findall(r'[\u4e00-\u9fa5]|\w+', clean_content) + word_count = len(words) + + # 按平均每分钟200字的速度计算 + reading_speed = 200 + reading_minutes = math.ceil(word_count / reading_speed) + + # 如果阅读时间少于1分钟,则显示为1分钟 + if reading_minutes < 1: + reading_minutes = 1 + + reading_time_html = f'

预计阅读时间:{reading_minutes} 分钟

' + + return reading_time_html + content + + +plugin = ReadingTimePlugin() \ No newline at end of file diff --git a/plugins/seo_optimizer/__init__.py b/plugins/seo_optimizer/__init__.py new file mode 100644 index 0000000..e88afca --- /dev/null +++ b/plugins/seo_optimizer/__init__.py @@ -0,0 +1 @@ +# This file makes this a Python package diff --git a/plugins/seo_optimizer/plugin.py b/plugins/seo_optimizer/plugin.py new file mode 100644 index 0000000..b5b19a3 --- /dev/null +++ b/plugins/seo_optimizer/plugin.py @@ -0,0 +1,142 @@ +import json +from django.utils.html import strip_tags +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 + + +class SeoOptimizerPlugin(BasePlugin): + PLUGIN_NAME = 'SEO 优化器' + PLUGIN_DESCRIPTION = '为文章、页面等提供 SEO 优化,动态生成 meta 标签和 JSON-LD 结构化数据。' + PLUGIN_VERSION = '0.2.0' + PLUGIN_AUTHOR = 'liuangliangyy' + + def register_hooks(self): + hooks.register('head_meta', self.dispatch_seo_generation) + + def _get_article_seo_data(self, context, request, blog_setting): + article = context.get('article') + if not isinstance(article, Article): + return None + + description = strip_tags(article.body)[:150] + keywords = ",".join([tag.name for tag in article.tags.all()]) or blog_setting.site_keywords + + meta_tags = f''' + + + + + + + + + ''' + for tag in article.tags.all(): + meta_tags += f'' + meta_tags += f'' + + structured_data = { + "@context": "https://schema.org", + "@type": "Article", + "mainEntityOfPage": {"@type": "WebPage", "@id": request.build_absolute_uri()}, + "headline": article.title, + "description": description, + "image": request.build_absolute_uri(article.get_first_image_url()), + "datePublished": article.pub_time.isoformat(), + "dateModified": article.last_modify_time.isoformat(), + "author": {"@type": "Person", "name": article.author.username}, + "publisher": {"@type": "Organization", "name": blog_setting.site_name} + } + if not structured_data.get("image"): + del structured_data["image"] + + return { + "title": f"{article.title} | {blog_setting.site_name}", + "description": description, + "keywords": keywords, + "meta_tags": meta_tags, + "json_ld": structured_data + } + + def _get_category_seo_data(self, context, request, blog_setting): + category_name = context.get('tag_name') + if not category_name: + return None + + category = Category.objects.filter(name=category_name).first() + if not category: + return None + + title = f"{category.name} | {blog_setting.site_name}" + description = strip_tags(category.name) or blog_setting.site_description + keywords = category.name + + # BreadcrumbList structured data for category page + breadcrumb_items = [{"@type": "ListItem", "position": 1, "name": "首页", "item": request.build_absolute_uri('/')}] + breadcrumb_items.append({"@type": "ListItem", "position": 2, "name": category.name, "item": request.build_absolute_uri()}) + + structured_data = { + "@context": "https://schema.org", + "@type": "BreadcrumbList", + "itemListElement": breadcrumb_items + } + + return { + "title": title, + "description": description, + "keywords": keywords, + "meta_tags": "", + "json_ld": structured_data + } + + def _get_default_seo_data(self, context, request, blog_setting): + # Homepage and other default pages + structured_data = { + "@context": "https://schema.org", + "@type": "WebSite", + "url": request.build_absolute_uri('/'), + "potentialAction": { + "@type": "SearchAction", + "target": f"{request.build_absolute_uri('/search/')}?q={{search_term_string}}", + "query-input": "required name=search_term_string" + } + } + return { + "title": f"{blog_setting.site_name} | {blog_setting.site_description}", + "description": blog_setting.site_description, + "keywords": blog_setting.site_keywords, + "meta_tags": "", + "json_ld": structured_data + } + + def dispatch_seo_generation(self, metas, context): + request = context.get('request') + if not request: + return metas + + view_name = request.resolver_match.view_name + blog_setting = get_blog_setting() + + seo_data = None + if view_name == 'blog:detailbyid': + seo_data = self._get_article_seo_data(context, request, blog_setting) + elif view_name == 'blog:category_detail': + seo_data = self._get_category_seo_data(context, request, blog_setting) + + if not seo_data: + seo_data = self._get_default_seo_data(context, request, blog_setting) + + json_ld_script = f'' + + return f""" + {seo_data.get("title", "")} + + + {seo_data.get("meta_tags", "")} + {json_ld_script} + """ + +plugin = SeoOptimizerPlugin() diff --git a/plugins/view_count/__init__.py b/plugins/view_count/__init__.py new file mode 100644 index 0000000..8804fdf --- /dev/null +++ b/plugins/view_count/__init__.py @@ -0,0 +1 @@ +# This file makes this a Python package \ No newline at end of file diff --git a/plugins/view_count/plugin.py b/plugins/view_count/plugin.py new file mode 100644 index 0000000..15e9d94 --- /dev/null +++ b/plugins/view_count/plugin.py @@ -0,0 +1,18 @@ +from djangoblog.plugin_manage.base_plugin import BasePlugin +from djangoblog.plugin_manage import hooks + + +class ViewCountPlugin(BasePlugin): + PLUGIN_NAME = '文章浏览次数统计' + PLUGIN_DESCRIPTION = '统计文章的浏览次数' + PLUGIN_VERSION = '0.1.0' + PLUGIN_AUTHOR = 'liangliangyy' + + def register_hooks(self): + hooks.register('after_article_body_get', self.record_view) + + def record_view(self, article, *args, **kwargs): + article.viewed() + + +plugin = ViewCountPlugin() \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..9dc5c935191f166db408850beb747475a262f65f GIT binary patch literal 2554 zcmZ{mOK)0H41~|RQhy3jxa83;x~aOVRHt-$MBCMc>m$SHk)3NsCx724O z&svob%XMU|V{iQC@?R zZ~0G!W+z_|B@^!EYb0|a8|zFJJ(1fNe%^|{En8uk>3b5kw*sb!x=F1+XweA^2Zpom&^VXcC#kB7{YUtyk1AW8lRCsH7kc&9|2FJZDW6fPxwcK<4UuCUBdsXLVs`_5F zp~0oR=sQS>?<%PjW*zBU@cbYY3-!J}L^}_3Y27N;PkG)pk*uJsc&?t#R3o*J(X1SA zka;NaQGO#GYHJxbBbSkJp-k9@@&PlNs$w3EcPR@sF|TltTB6Tpl&WX?P!AFM`gAq# ziDP5!b%x?N`7!_PG~o%JQRKX9Y6p=$>EBXOM*7a}6;HOi-71ev8|^_li^@^eSj@w__0A3aLAaD3lW$cY-+ejf+0D0n;c*g?m`=Y9 z#D{NVKaQOf&bHqN|K6p!G41^vmi8TR=TIe^a2}m??@)Ypmc4|+%#Zt&bBpa!Y_Lna z95ZK`d!>na86B&$`)xt#Oe-&k^ISIS%h_8C0ec(O{{Ln{w6Q!`KVv#@hd&K=)9UJoM~W6el-zM7!{x**T=1X z^wa1z+L2b5chAc%ZKb?k2fY03=7b3E0}!J+D^ z`Om~yc~RJ~yuIGH-QLq%`|ZTuPLXcJX{%xE{f6^yk|#Rdx2k=` SS`X?#O)JeKo3nk{t@?jbHFwMa literal 0 HcmV?d00001 diff --git a/servermanager/MemcacheStorage.py b/servermanager/MemcacheStorage.py new file mode 100644 index 0000000..38a7990 --- /dev/null +++ b/servermanager/MemcacheStorage.py @@ -0,0 +1,32 @@ +from werobot.session import SessionStorage +from werobot.utils import json_loads, json_dumps + +from djangoblog.utils import cache + + +class MemcacheStorage(SessionStorage): + def __init__(self, prefix='ws_'): + self.prefix = prefix + self.cache = cache + + @property + def is_available(self): + value = "1" + self.set('checkavaliable', value=value) + return value == self.get('checkavaliable') + + def key_name(self, s): + return '{prefix}{s}'.format(prefix=self.prefix, s=s) + + def get(self, id): + id = self.key_name(id) + session_json = self.cache.get(id) or '{}' + return json_loads(session_json) + + def set(self, id, value): + id = self.key_name(id) + self.cache.set(id, json_dumps(value)) + + def delete(self, id): + id = self.key_name(id) + self.cache.delete(id) diff --git a/servermanager/__init__.py b/servermanager/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/servermanager/admin.py b/servermanager/admin.py new file mode 100644 index 0000000..f26f4f6 --- /dev/null +++ b/servermanager/admin.py @@ -0,0 +1,19 @@ +from django.contrib import admin +# Register your models here. + + +class CommandsAdmin(admin.ModelAdmin): + list_display = ('title', 'command', 'describe') + + +class EmailSendLogAdmin(admin.ModelAdmin): + list_display = ('title', 'emailto', 'send_result', 'creation_time') + readonly_fields = ( + 'title', + 'emailto', + 'send_result', + 'creation_time', + 'content') + + def has_add_permission(self, request): + return False diff --git a/servermanager/api/__init__.py b/servermanager/api/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/servermanager/api/__init__.py @@ -0,0 +1 @@ + diff --git a/servermanager/api/blogapi.py b/servermanager/api/blogapi.py new file mode 100644 index 0000000..8a4d6ac --- /dev/null +++ b/servermanager/api/blogapi.py @@ -0,0 +1,27 @@ +from haystack.query import SearchQuerySet + +from blog.models import Article, Category + + +class BlogApi: + def __init__(self): + self.searchqueryset = SearchQuerySet() + self.searchqueryset.auto_query('') + self.__max_takecount__ = 8 + + def search_articles(self, query): + sqs = self.searchqueryset.auto_query(query) + sqs = sqs.load_all() + return sqs[:self.__max_takecount__] + + def get_category_lists(self): + return Category.objects.all() + + def get_category_articles(self, categoryname): + articles = Article.objects.filter(category__name=categoryname) + if articles: + return articles[:self.__max_takecount__] + return None + + def get_recent_articles(self): + return Article.objects.all()[:self.__max_takecount__] diff --git a/servermanager/api/commonapi.py b/servermanager/api/commonapi.py new file mode 100644 index 0000000..83ad9ff --- /dev/null +++ b/servermanager/api/commonapi.py @@ -0,0 +1,64 @@ +import logging +import os + +import openai + +from servermanager.models import commands + +logger = logging.getLogger(__name__) + +openai.api_key = os.environ.get('OPENAI_API_KEY') +if os.environ.get('HTTP_PROXY'): + openai.proxy = os.environ.get('HTTP_PROXY') + + +class ChatGPT: + + @staticmethod + def chat(prompt): + try: + completion = openai.ChatCompletion.create(model="gpt-3.5-turbo", + messages=[{"role": "user", "content": prompt}]) + return completion.choices[0].message.content + except Exception as e: + logger.error(e) + return "服务器出错了" + + +class CommandHandler: + def __init__(self): + self.commands = commands.objects.all() + + def run(self, title): + """ + 运行命令 + :param title: 命令 + :return: 返回命令执行结果 + """ + cmd = list( + filter( + lambda x: x.title.upper() == title.upper(), + self.commands)) + if cmd: + return self.__run_command__(cmd[0].command) + else: + return "未找到相关命令,请输入hepme获得帮助。" + + def __run_command__(self, cmd): + try: + res = os.popen(cmd).read() + return res + except BaseException: + return '命令执行出错!' + + def get_help(self): + rsp = '' + for cmd in self.commands: + rsp += '{c}:{d}\n'.format(c=cmd.title, d=cmd.describe) + return rsp + + +if __name__ == '__main__': + chatbot = ChatGPT() + prompt = "写一篇1000字关于AI的论文" + print(chatbot.chat(prompt)) diff --git a/servermanager/apps.py b/servermanager/apps.py new file mode 100644 index 0000000..03cc38d --- /dev/null +++ b/servermanager/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class ServermanagerConfig(AppConfig): + name = 'servermanager' diff --git a/servermanager/migrations/0001_initial.py b/servermanager/migrations/0001_initial.py new file mode 100644 index 0000000..bbdbf77 --- /dev/null +++ b/servermanager/migrations/0001_initial.py @@ -0,0 +1,45 @@ +# Generated by Django 4.1.7 on 2023-03-02 07:14 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='commands', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=300, verbose_name='命令标题')), + ('command', models.CharField(max_length=2000, verbose_name='命令')), + ('describe', models.CharField(max_length=300, verbose_name='命令描述')), + ('created_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), + ('last_mod_time', models.DateTimeField(auto_now=True, verbose_name='修改时间')), + ], + options={ + 'verbose_name': '命令', + 'verbose_name_plural': '命令', + }, + ), + migrations.CreateModel( + name='EmailSendLog', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('emailto', models.CharField(max_length=300, verbose_name='收件人')), + ('title', models.CharField(max_length=2000, verbose_name='邮件标题')), + ('content', models.TextField(verbose_name='邮件内容')), + ('send_result', models.BooleanField(default=False, verbose_name='结果')), + ('created_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), + ], + options={ + 'verbose_name': '邮件发送log', + 'verbose_name_plural': '邮件发送log', + 'ordering': ['-created_time'], + }, + ), + ] diff --git a/servermanager/migrations/0002_alter_emailsendlog_options_and_more.py b/servermanager/migrations/0002_alter_emailsendlog_options_and_more.py new file mode 100644 index 0000000..4858857 --- /dev/null +++ b/servermanager/migrations/0002_alter_emailsendlog_options_and_more.py @@ -0,0 +1,32 @@ +# Generated by Django 4.2.5 on 2023-09-06 13:19 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('servermanager', '0001_initial'), + ] + + operations = [ + migrations.AlterModelOptions( + name='emailsendlog', + options={'ordering': ['-creation_time'], 'verbose_name': '邮件发送log', 'verbose_name_plural': '邮件发送log'}, + ), + migrations.RenameField( + model_name='commands', + old_name='created_time', + new_name='creation_time', + ), + migrations.RenameField( + model_name='commands', + old_name='last_mod_time', + new_name='last_modify_time', + ), + migrations.RenameField( + model_name='emailsendlog', + old_name='created_time', + new_name='creation_time', + ), + ] diff --git a/servermanager/migrations/__init__.py b/servermanager/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/servermanager/models.py b/servermanager/models.py new file mode 100644 index 0000000..4326c65 --- /dev/null +++ b/servermanager/models.py @@ -0,0 +1,33 @@ +from django.db import models + + +# Create your models here. +class commands(models.Model): + title = models.CharField('命令标题', max_length=300) + command = models.CharField('命令', max_length=2000) + describe = models.CharField('命令描述', max_length=300) + creation_time = models.DateTimeField('创建时间', auto_now_add=True) + last_modify_time = models.DateTimeField('修改时间', auto_now=True) + + def __str__(self): + return self.title + + class Meta: + verbose_name = '命令' + verbose_name_plural = verbose_name + + +class EmailSendLog(models.Model): + emailto = models.CharField('收件人', max_length=300) + title = models.CharField('邮件标题', max_length=2000) + content = models.TextField('邮件内容') + send_result = models.BooleanField('结果', default=False) + creation_time = models.DateTimeField('创建时间', auto_now_add=True) + + def __str__(self): + return self.title + + class Meta: + verbose_name = '邮件发送log' + verbose_name_plural = verbose_name + ordering = ['-creation_time'] diff --git a/servermanager/robot.py b/servermanager/robot.py new file mode 100644 index 0000000..7b45736 --- /dev/null +++ b/servermanager/robot.py @@ -0,0 +1,187 @@ +import logging +import os +import re + +import jsonpickle +from django.conf import settings +from werobot import WeRoBot +from werobot.replies import ArticlesReply, Article +from werobot.session.filestorage import FileStorage + +from djangoblog.utils import get_sha256 +from servermanager.api.blogapi import BlogApi +from servermanager.api.commonapi import ChatGPT, CommandHandler +from .MemcacheStorage import MemcacheStorage + +robot = WeRoBot(token=os.environ.get('DJANGO_WEROBOT_TOKEN') + or 'lylinux', enable_session=True) +memstorage = MemcacheStorage() +if memstorage.is_available: + robot.config['SESSION_STORAGE'] = memstorage +else: + if os.path.exists(os.path.join(settings.BASE_DIR, 'werobot_session')): + os.remove(os.path.join(settings.BASE_DIR, 'werobot_session')) + robot.config['SESSION_STORAGE'] = FileStorage(filename='werobot_session') + +blogapi = BlogApi() +cmd_handler = CommandHandler() +logger = logging.getLogger(__name__) + + +def convert_to_article_reply(articles, message): + reply = ArticlesReply(message=message) + from blog.templatetags.blog_tags import truncatechars_content + for post in articles: + imgs = re.findall(r'(?:http\:|https\:)?\/\/.*\.(?:png|jpg)', post.body) + imgurl = '' + if imgs: + imgurl = imgs[0] + article = Article( + title=post.title, + description=truncatechars_content(post.body), + img=imgurl, + url=post.get_full_url() + ) + reply.add_article(article) + return reply + + +@robot.filter(re.compile(r"^\?.*")) +def search(message, session): + s = message.content + searchstr = str(s).replace('?', '') + result = blogapi.search_articles(searchstr) + if result: + articles = list(map(lambda x: x.object, result)) + reply = convert_to_article_reply(articles, message) + return reply + else: + return '没有找到相关文章。' + + +@robot.filter(re.compile(r'^category\s*$', re.I)) +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, session): + articles = blogapi.get_recent_articles() + if articles: + reply = convert_to_article_reply(articles, message) + return reply + else: + return "暂时还没有文章" + + +@robot.filter(re.compile('^help$', re.I)) +def help(message, session): + return '''欢迎关注! + 默认会与图灵机器人聊天~~ + 你可以通过下面这些命令来获得信息 + ?关键字搜索文章. + 如?python. + category获得文章分类目录及文章数. + category-***获得该分类目录文章 + 如category-python + recent获得最新文章 + help获得帮助. + weather:获得天气 + 如weather:西安 + idcard:获得身份证信息 + 如idcard:61048119xxxxxxxxxx + music:音乐搜索 + 如music:阴天快乐 + PS:以上标点符号都不支持中文标点~~ + ''' + + +@robot.filter(re.compile(r'^weather\:.*$', re.I)) +def weather(message, session): + return "建设中..." + + +@robot.filter(re.compile(r'^idcard\:.*$', re.I)) +def idcard(message, session): + return "建设中..." + + +@robot.handler +def echo(message, session): + handler = MessageHandler(message, session) + return handler.handler() + + +class MessageHandler: + def __init__(self, message, session): + userid = message.source + self.message = message + self.session = session + self.userid = userid + try: + info = session[userid] + self.userinfo = jsonpickle.decode(info) + except Exception as e: + userinfo = WxUserInfo() + self.userinfo = userinfo + + @property + def is_admin(self): + return self.userinfo.isAdmin + + @property + def is_password_set(self): + return self.userinfo.isPasswordSet + + def save_session(self): + info = jsonpickle.encode(self.userinfo) + self.session[self.userid] = info + + def handler(self): + info = self.message.content + + if self.userinfo.isAdmin and info.upper() == 'EXIT': + self.userinfo = WxUserInfo() + self.save_session() + return "退出成功" + if info.upper() == 'ADMIN': + self.userinfo.isAdmin = True + self.save_session() + return "输入管理员密码" + if self.userinfo.isAdmin and not self.userinfo.isPasswordSet: + passwd = settings.WXADMIN + if settings.TESTING: + passwd = '123' + if passwd.upper() == get_sha256(get_sha256(info)).upper(): + self.userinfo.isPasswordSet = True + self.save_session() + return "验证通过,请输入命令或者要执行的命令代码:输入helpme获得帮助" + else: + if self.userinfo.Count >= 3: + self.userinfo = WxUserInfo() + self.save_session() + return "超过验证次数" + self.userinfo.Count += 1 + self.save_session() + return "验证失败,请重新输入管理员密码:" + if self.userinfo.isAdmin and self.userinfo.isPasswordSet: + if self.userinfo.Command != '' and info.upper() == 'Y': + return cmd_handler.run(self.userinfo.Command) + else: + if info.upper() == 'HELPME': + return cmd_handler.get_help() + self.userinfo.Command = info + self.save_session() + return "确认执行: " + info + " 命令?" + + return ChatGPT.chat(info) + + +class WxUserInfo(): + def __init__(self): + self.isAdmin = False + self.isPasswordSet = False + self.Count = 0 + self.Command = '' diff --git a/servermanager/tests.py b/servermanager/tests.py new file mode 100644 index 0000000..22a6689 --- /dev/null +++ b/servermanager/tests.py @@ -0,0 +1,79 @@ +from django.test import Client, RequestFactory, TestCase +from django.utils import timezone +from werobot.messages.messages import TextMessage + +from accounts.models import BlogUser +from blog.models import Category, Article +from servermanager.api.commonapi import ChatGPT +from .models import commands +from .robot import MessageHandler, CommandHandler +from .robot import search, category, recents + + +# Create your tests here. +class ServerManagerTest(TestCase): + def setUp(self): + self.client = Client() + self.factory = RequestFactory() + + def test_chat_gpt(self): + content = ChatGPT.chat("你好") + self.assertIsNotNone(content) + + def test_validate_comment(self): + user = BlogUser.objects.create_superuser( + email="liangliangyy1@gmail.com", + username="liangliangyy1", + password="liangliangyy1") + + self.client.login(username='liangliangyy1', password='liangliangyy1') + + c = Category() + c.name = "categoryccc" + c.save() + + article = Article() + article.title = "nicetitleccc" + article.body = "nicecontentccc" + article.author = user + article.category = c + article.type = 'a' + article.status = 'p' + article.save() + s = TextMessage([]) + s.content = "nice" + rsp = search(s, None) + rsp = category(None, None) + self.assertIsNotNone(rsp) + rsp = recents(None, None) + self.assertTrue(rsp != '暂时还没有文章') + + cmd = commands() + cmd.title = "test" + cmd.command = "ls" + cmd.describe = "test" + cmd.save() + + cmdhandler = CommandHandler() + rsp = cmdhandler.run('test') + self.assertIsNotNone(rsp) + s.source = 'u' + s.content = 'test' + msghandler = MessageHandler(s, {}) + + # msghandler.userinfo.isPasswordSet = True + # msghandler.userinfo.isAdmin = True + msghandler.handler() + s.content = 'y' + msghandler.handler() + s.content = 'idcard:12321233' + msghandler.handler() + s.content = 'weather:上海' + msghandler.handler() + s.content = 'admin' + msghandler.handler() + s.content = '123' + msghandler.handler() + + s.content = 'exit' + msghandler.handler() diff --git a/servermanager/urls.py b/servermanager/urls.py new file mode 100644 index 0000000..8d134d2 --- /dev/null +++ b/servermanager/urls.py @@ -0,0 +1,10 @@ +from django.urls import path +from werobot.contrib.django import make_view + +from .robot import robot + +app_name = "servermanager" +urlpatterns = [ + path(r'robot', make_view(robot)), + +] diff --git a/servermanager/views.py b/servermanager/views.py new file mode 100644 index 0000000..60f00ef --- /dev/null +++ b/servermanager/views.py @@ -0,0 +1 @@ +# Create your views here. diff --git a/templates/account/forget_password.html b/templates/account/forget_password.html new file mode 100644 index 0000000..3384531 --- /dev/null +++ b/templates/account/forget_password.html @@ -0,0 +1,30 @@ +{% extends 'share_layout/base_account.html' %} +{% load i18n %} +{% load static %} +{% block content %} +
+ + + + + +

+ Home Page + | + login page +

+ +
+{% endblock %} \ No newline at end of file diff --git a/templates/account/login.html b/templates/account/login.html new file mode 100644 index 0000000..cff8d33 --- /dev/null +++ b/templates/account/login.html @@ -0,0 +1,46 @@ +{% extends 'share_layout/base_account.html' %} +{% load static %} +{% load i18n %} +{% block content %} +
+ + + + + +

+ + {% trans 'Create Account' %} + + | + Home Page + | + + {% trans 'Forget Password' %} + +

+ +
+{% endblock %} \ No newline at end of file diff --git a/templates/account/registration_form.html b/templates/account/registration_form.html new file mode 100644 index 0000000..65e7549 --- /dev/null +++ b/templates/account/registration_form.html @@ -0,0 +1,29 @@ +{% extends 'share_layout/base_account.html' %} +{% load static %} +{% block content %} +
+ + + + + +

+ Sign In +

+ +
+{% endblock %} \ No newline at end of file diff --git a/templates/account/result.html b/templates/account/result.html new file mode 100644 index 0000000..23c9094 --- /dev/null +++ b/templates/account/result.html @@ -0,0 +1,27 @@ +{% extends 'share_layout/base.html' %} +{% load i18n %} +{% block header %} + {{ title }} +{% endblock %} +{% block content %} +
+ +
+{% endblock %} \ No newline at end of file diff --git a/templates/blog/article_archives.html b/templates/blog/article_archives.html new file mode 100644 index 0000000..959319e --- /dev/null +++ b/templates/blog/article_archives.html @@ -0,0 +1,60 @@ +{% extends 'share_layout/base.html' %} +{% load blog_tags %} +{% load cache %} +{% load i18n %} +{% block header %} + + {% trans 'article archive' %} | {{ SITE_DESCRIPTION }} + + + + + + + + + +{% endblock %} +{% block content %} +
+
+ +
+ +

{% trans 'article archive' %}

+
+ +
+ + {% regroup article_list by pub_time.year as year_post_group %} +
    + {% for year in year_post_group %} +
  • {{ year.grouper }} {% trans 'year' %} + {% regroup year.list by pub_time.month as month_post_group %} +
      + {% for month in month_post_group %} +
    • {{ month.grouper }} {% trans 'month' %} + +
    • + {% endfor %} +
    +
  • + {% endfor %} +
+
+
+
+ +{% endblock %} + + +{% block sidebar %} + {% load_sidebar user 'i' %} +{% endblock %} + + diff --git a/templates/blog/article_detail.html b/templates/blog/article_detail.html new file mode 100644 index 0000000..a74a0db --- /dev/null +++ b/templates/blog/article_detail.html @@ -0,0 +1,52 @@ +{% extends 'share_layout/base.html' %} +{% load blog_tags %} + +{% block header %} +{% endblock %} +{% block content %} +
+
+ {% load_article_detail article False user %} + + {% if article.type == 'a' %} + + {% endif %} + +
+ {% if article.comment_status == "o" and OPEN_SITE_COMMENT %} + + + {% include 'comments/tags/comment_list.html' %} + {% if user.is_authenticated %} + {% include 'comments/tags/post_comment.html' %} + {% else %} +
+

您还没有登录,请您登录后发表评论。 +

+ + {% load oauth_tags %} + {% load_oauth_applications request %} + +
+ {% endif %} + {% endif %} +
+ +{% endblock %} + +{% block sidebar %} + {% load_sidebar user "p" %} +{% endblock %} \ No newline at end of file diff --git a/templates/blog/article_index.html b/templates/blog/article_index.html new file mode 100644 index 0000000..0ee6150 --- /dev/null +++ b/templates/blog/article_index.html @@ -0,0 +1,42 @@ +{% extends 'share_layout/base.html' %} +{% load blog_tags %} +{% load cache %} +{% block header %} + {% if tag_name %} + {{ page_type }}:{{ tag_name }} | {{ SITE_DESCRIPTION }} + {% comment %}{% endcomment %} + {% else %} + {{ SITE_NAME }} | {{ SITE_DESCRIPTION }} + {% endif %} + + + + + + + +{% endblock %} +{% block content %} +
+
+ {% if page_type and tag_name %} +
+ +

{{ page_type }}:{{ tag_name }}

+
+ {% endif %} + + {% for article in article_list %} + {% load_article_detail article True user %} + {% endfor %} + {% if is_paginated %} + {% load_pagination_info page_obj page_type tag_name %} + + {% endif %} +
+
+ +{% endblock %} +{% block sidebar %} + {% load_sidebar user linktype %} +{% endblock %} \ No newline at end of file diff --git a/templates/blog/error_page.html b/templates/blog/error_page.html new file mode 100644 index 0000000..d41cfb6 --- /dev/null +++ b/templates/blog/error_page.html @@ -0,0 +1,45 @@ +{% extends 'share_layout/base.html' %} +{% load blog_tags %} +{% load cache %} +{% block header %} + {% if tag_name %} + {% if statuscode == '404' %} + 404 NotFound + {% elif statuscode == '403' %} + Permission Denied + {% elif statuscode == '500' %} + 500 Error + {% else %} + + {% endif %} + {% comment %}{% endcomment %} + {% else %} + {{ SITE_NAME }} | {{ SITE_DESCRIPTION }} + {% endif %} + + + + + + + +{% endblock %} +{% block content %} +
+
+ +
+

{{ message }}

+
+ +
+
+ +{% endblock %} + + +{% block sidebar %} + {% load_sidebar user 'i' %} +{% endblock %} + + diff --git a/templates/blog/links_list.html b/templates/blog/links_list.html new file mode 100644 index 0000000..ccecbea --- /dev/null +++ b/templates/blog/links_list.html @@ -0,0 +1,44 @@ +{% extends 'share_layout/base.html' %} +{% load blog_tags %} +{% load cache %} +{% block header %} + + 友情链接 | {{ SITE_DESCRIPTION }} + + + + + + + + + +{% endblock %} +{% block content %} +
+
+ +
+ +

友情链接

+
+ +
+ +
+
+
+ +{% endblock %} + + +{% block sidebar %} + {% load_sidebar user 'i' %} +{% endblock %} + + diff --git a/templates/blog/tags/article_info.html b/templates/blog/tags/article_info.html new file mode 100644 index 0000000..3deec44 --- /dev/null +++ b/templates/blog/tags/article_info.html @@ -0,0 +1,74 @@ +{% load blog_tags %} +{% load cache %} +{% load i18n %} +
+
+ +

+ {% if isindex %} + {% if article.article_order > 0 %} + 【{% trans 'pin to top' %}】{{ article.title }} + {% else %} + {{ article.title }} + {% endif %} + + {% else %} + {{ article.title }} + {% endif %} +

+ +
+ {% if article.type == 'a' %} + {% if not isindex %} + {% cache 36000 breadcrumb article.pk %} + {% load_breadcrumb article %} + {% endcache %} + {% endif %} + {% endif %} +
+ +
+ {% if isindex %} + {{ article.body|custom_markdown|escape|truncatechars_content }} +

Read more

+ {% else %} + + {% if article.show_toc %} + {% get_markdown_toc article.body as toc %} + {% trans 'toc' %}: + {{ toc|safe }} + +
+ {% endif %} +
+ + {{ article.body|custom_markdown|escape }} + +
+ {% endif %} + +
+ + {% load_article_metas article user %} + +
\ No newline at end of file diff --git a/templates/blog/tags/article_meta_info.html b/templates/blog/tags/article_meta_info.html new file mode 100644 index 0000000..cb6111c --- /dev/null +++ b/templates/blog/tags/article_meta_info.html @@ -0,0 +1,59 @@ +{% load i18n %} +{% load blog_tags %} + + + + + diff --git a/templates/blog/tags/article_pagination.html b/templates/blog/tags/article_pagination.html new file mode 100644 index 0000000..95514ff --- /dev/null +++ b/templates/blog/tags/article_pagination.html @@ -0,0 +1,17 @@ +{% load i18n %} + \ No newline at end of file diff --git a/templates/blog/tags/article_tag_list.html b/templates/blog/tags/article_tag_list.html new file mode 100644 index 0000000..c8ba474 --- /dev/null +++ b/templates/blog/tags/article_tag_list.html @@ -0,0 +1,19 @@ +{% load i18n %} +{% if article_tags_list %} +
+
+ {% trans 'tags' %} +
+
+ + {% for url,count,tag,color in article_tags_list %} + + {{ tag.name }} + {{ count }} + + {% endfor %} + +
+
+{% endif %} diff --git a/templates/blog/tags/breadcrumb.html b/templates/blog/tags/breadcrumb.html new file mode 100644 index 0000000..67087d5 --- /dev/null +++ b/templates/blog/tags/breadcrumb.html @@ -0,0 +1,19 @@ + + diff --git a/templates/blog/tags/sidebar.html b/templates/blog/tags/sidebar.html new file mode 100644 index 0000000..f70544c --- /dev/null +++ b/templates/blog/tags/sidebar.html @@ -0,0 +1,136 @@ +{% load blog_tags %} +{% load i18n %} + diff --git a/templates/comments/tags/comment_item.html b/templates/comments/tags/comment_item.html new file mode 100644 index 0000000..ebb0388 --- /dev/null +++ b/templates/comments/tags/comment_item.html @@ -0,0 +1,34 @@ +{% load blog_tags %} +
  • +
    + + + +

    {{ comment_item.body|escape|comment_markdown }}

    + +
    + +
  • \ No newline at end of file diff --git a/templates/comments/tags/comment_item_tree.html b/templates/comments/tags/comment_item_tree.html new file mode 100644 index 0000000..a9decd1 --- /dev/null +++ b/templates/comments/tags/comment_item_tree.html @@ -0,0 +1,54 @@ +{% load blog_tags %} +
  • +
    + + + +

    + {% if comment_item.parent_comment %} +

    + {% endif %} +

    + +

    {{ comment_item.body|escape|comment_markdown }}

    + + +
    + +
  • +{% query article_comments parent_comment=comment_item as cc_comments %} +{% for cc in cc_comments %} + {% with comment_item=cc template_name="comments/tags/comment_item_tree.html" %} + {% if depth >= 1 %} + {% include template_name %} + {% else %} + {% with depth=depth|add:1 %} + {% include template_name %} + {% endwith %} + {% endif %} + {% endwith %} +{% endfor %} \ No newline at end of file diff --git a/templates/comments/tags/comment_list.html b/templates/comments/tags/comment_list.html new file mode 100644 index 0000000..4092161 --- /dev/null +++ b/templates/comments/tags/comment_list.html @@ -0,0 +1,45 @@ + +
    + {% load blog_tags %} + {% load comments_tags %} + {% load cache %} + + + {% if article_comments %} +
    +
      + {# {% query article_comments parent_comment=None as parent_comments %}#} + {% for comment_item in p_comments %} + + {% with 0 as depth %} + {% include "comments/tags/comment_item_tree.html" %} + {% endwith %} + {% endfor %} + +
    + +
    +
    + {% endif %} +
    + +
    \ No newline at end of file diff --git a/templates/comments/tags/post_comment.html b/templates/comments/tags/post_comment.html new file mode 100644 index 0000000..3ae5a27 --- /dev/null +++ b/templates/comments/tags/post_comment.html @@ -0,0 +1,33 @@ +
    + +
    +

    发表评论 + +

    +
    {% csrf_token %} +

    + {{ form.body.label_tag }} + + {{ form.body }} + {{ form.body.errors }} +

    + {{ form.parent_comment_id }} +
    + {% if COMMENT_NEED_REVIEW %} + 支持markdown,评论经审核后才会显示。 + {% else %} + 支持markdown。 + {% endif %} + + +
    +
    +
    + +
    + + diff --git a/templates/oauth/bindsuccess.html b/templates/oauth/bindsuccess.html new file mode 100644 index 0000000..4bee77c --- /dev/null +++ b/templates/oauth/bindsuccess.html @@ -0,0 +1,22 @@ +{% extends 'share_layout/base.html' %} +{% block header %} + {{ title }} +{% endblock %} +{% block content %} +
    +
    + +
    + +

    {{ content }}

    +
    +
    +
    + + 登录 + | + 回到首页 +
    +
    +
    +{% endblock %} \ No newline at end of file diff --git a/templates/oauth/oauth_applications.html b/templates/oauth/oauth_applications.html new file mode 100644 index 0000000..a841ad2 --- /dev/null +++ b/templates/oauth/oauth_applications.html @@ -0,0 +1,13 @@ +{% load i18n %} + diff --git a/templates/oauth/require_email.html b/templates/oauth/require_email.html new file mode 100644 index 0000000..3adef12 --- /dev/null +++ b/templates/oauth/require_email.html @@ -0,0 +1,46 @@ +{% extends 'share_layout/base_account.html' %} + +{% load static %} +{% block content %} +
    + + + + + +

    + 登录 +

    + +
    +{% endblock %} \ No newline at end of file diff --git a/templates/owntracks/show_log_dates.html b/templates/owntracks/show_log_dates.html new file mode 100644 index 0000000..7dbba21 --- /dev/null +++ b/templates/owntracks/show_log_dates.html @@ -0,0 +1,17 @@ + + + + + 记录日期 + + + +
      + {% for date in results %} +
    • + {{ date }} +
    • + {% endfor %} +
    + + \ No newline at end of file diff --git a/templates/owntracks/show_maps.html b/templates/owntracks/show_maps.html new file mode 100644 index 0000000..3aeda36 --- /dev/null +++ b/templates/owntracks/show_maps.html @@ -0,0 +1,135 @@ + + + + + + + 运动轨迹 + + + +
    + + + + + + + + \ No newline at end of file diff --git a/templates/search/indexes/blog/article_text.txt b/templates/search/indexes/blog/article_text.txt new file mode 100644 index 0000000..4f9ca76 --- /dev/null +++ b/templates/search/indexes/blog/article_text.txt @@ -0,0 +1,3 @@ +{{ object.title }} +{{ object.author.username }} +{{ object.body }} \ No newline at end of file diff --git a/templates/search/search.html b/templates/search/search.html new file mode 100644 index 0000000..1404c60 --- /dev/null +++ b/templates/search/search.html @@ -0,0 +1,66 @@ +{% extends 'share_layout/base.html' %} +{% load blog_tags %} +{% block header %} + {{ SITE_NAME }} | {{ SITE_DESCRIPTION }} + + + + + + + +{% endblock %} +{% block content %} +
    +
    + {% if query %} +
    + {% if suggestion %} +

    + 已显示 “{{ suggestion }}” 的搜索结果。   + 仍然搜索:{{ query }}
    +

    + {% else %} +

    + 搜索:{{ query }}    +

    + {% endif %} +
    + {% endif %} + {% if query and page.object_list %} + {% for article in page.object_list %} + {% load_article_detail article.object True user %} + {% endfor %} + {% if page.has_previous or page.has_next %} + + + {% endif %} + {% else %} +
    + +

    哎呀,关键字:{{ query }}没有找到结果,要不换个词再试试?

    +
    + {% endif %} +
    +
    +{% endblock %} + + +{% block sidebar %} + {% load_sidebar request.user 'i' %} +{% endblock %} + + diff --git a/templates/share_layout/adsense.html b/templates/share_layout/adsense.html new file mode 100644 index 0000000..8f99c55 --- /dev/null +++ b/templates/share_layout/adsense.html @@ -0,0 +1,6 @@ + \ No newline at end of file diff --git a/templates/share_layout/base.html b/templates/share_layout/base.html new file mode 100644 index 0000000..75d0df5 --- /dev/null +++ b/templates/share_layout/base.html @@ -0,0 +1,123 @@ +{% load static %} +{% load cache %} +{% load i18n %} +{% load compress %} + + + + + + + + + + {% block header %} + {% block title %}{{ SITE_NAME }}{% endblock %} + + + {% endblock %} + {% load blog_tags %} + {% head_meta %} + + + + + + + + + + + {% compress css %} + + + + {% comment %}{% endcomment %} + + + + {% block compress_css %} + {% endblock %} + {% endcompress %} + {% if GLOBAL_HEADER %} + {{ GLOBAL_HEADER|safe }} + {% endif %} + + + +
    + +
    + + {% block content %} + {% endblock %} + + + {% block sidebar %} + {% endblock %} + + +
    + {% include 'share_layout/footer.html' %} +
    + + +
    + + {% compress js %} + + + + + + {% block compress_js %} + {% endblock %} + {% endcompress %} + {% block footer %} + {% endblock %} +
    + diff --git a/templates/share_layout/base_account.html b/templates/share_layout/base_account.html new file mode 100644 index 0000000..c00d842 --- /dev/null +++ b/templates/share_layout/base_account.html @@ -0,0 +1,47 @@ + + + + {% load static %} + + + + + + + + + {{ SITE_NAME }} | {{ SITE_DESCRIPTION }} + + {% load compress %} + {% compress css %} + + + + + + + + + + {% endcompress %} + {% compress js %} + + + {% endcompress %} + + + + + +{% block content %} +{% endblock %} + + + + + + + \ No newline at end of file diff --git a/templates/share_layout/footer.html b/templates/share_layout/footer.html new file mode 100644 index 0000000..cd86a29 --- /dev/null +++ b/templates/share_layout/footer.html @@ -0,0 +1,56 @@ + + + diff --git a/templates/share_layout/nav.html b/templates/share_layout/nav.html new file mode 100644 index 0000000..24d4da6 --- /dev/null +++ b/templates/share_layout/nav.html @@ -0,0 +1,30 @@ +{% load i18n %} + + \ No newline at end of file diff --git a/templates/share_layout/nav_node.html b/templates/share_layout/nav_node.html new file mode 100644 index 0000000..c266880 --- /dev/null +++ b/templates/share_layout/nav_node.html @@ -0,0 +1,19 @@ + + + From ff47ce714cfe8823b2198a2fe17ebd087e84fb8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=9B=AA?= <2518549229@qq.com> Date: Sat, 11 Oct 2025 20:35:59 +0800 Subject: [PATCH 08/11] =?UTF-8?q?docs:=20=E6=B7=BB=E5=8A=A0DjangoBlog?= =?UTF-8?q?=E5=BC=80=E6=BA=90=E4=BB=A3=E7=A0=81=E6=B3=9B=E8=AF=BB=E6=8A=A5?= =?UTF-8?q?=E5=91=8A=E8=87=B3lx=5Fbranch?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/DjangoBlog_Reading_Report.md.docx | Bin 0 -> 354496 bytes src | 1 + 2 files changed, 1 insertion(+) create mode 100644 docs/DjangoBlog_Reading_Report.md.docx create mode 160000 src diff --git a/docs/DjangoBlog_Reading_Report.md.docx b/docs/DjangoBlog_Reading_Report.md.docx new file mode 100644 index 0000000000000000000000000000000000000000..ea1a6f725adf79c706c7129c562663d7bd47e7fd GIT binary patch literal 354496 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⊘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≠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 literal 0 HcmV?d00001 diff --git a/src b/src new file mode 160000 index 0000000..5b910b5 --- /dev/null +++ b/src @@ -0,0 +1 @@ +Subproject commit 5b910b544571890ca5000b46fcd8672852ac42e4 From 0ca44bcb2e5a563c8ebf5517e9e37cc522945cf3 Mon Sep 17 00:00:00 2001 From: pgxy4rpc3 <1662607537@qq.com> Date: Sun, 12 Oct 2025 15:19:07 +0800 Subject: [PATCH 09/11] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E6=A0=87=E6=B3=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/mxw_代码初步标注.docx | Bin 0 -> 15203 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/mxw_代码初步标注.docx diff --git a/doc/mxw_代码初步标注.docx b/doc/mxw_代码初步标注.docx new file mode 100644 index 0000000000000000000000000000000000000000..db5f64c2457c4af16eae1dc7cfb54e9a606888cb GIT binary patch literal 15203 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 Date: Sun, 12 Oct 2025 15:21:42 +0800 Subject: [PATCH 10/11] ADD file via upload --- 第四周.docx | Bin 0 -> 12638 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 第四周.docx diff --git a/第四周.docx b/第四周.docx new file mode 100644 index 0000000000000000000000000000000000000000..095fe1983d056c457164004f9cdd02dbc07e2562 GIT binary patch literal 12638 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 tdw+ocyZuGxE{|9nbrDp&D literal 0 HcmV?d00001 From ba7b2e7733833a23543fb72d7cc1c482df03f2da Mon Sep 17 00:00:00 2001 From: p2l7q3zht <1687267877@qq.com> Date: Sun, 12 Oct 2025 22:57:59 +0800 Subject: [PATCH 11/11] ADD file via upload --- zmy_代码标注.docx | Bin 0 -> 11836 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 zmy_代码标注.docx diff --git a/zmy_代码标注.docx b/zmy_代码标注.docx new file mode 100644 index 0000000000000000000000000000000000000000..a7748714eec0bca116b7f8100a595e248321fd65 GIT binary patch literal 11836 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