diff --git a/src/DjangoBlog-master/.coveragerc b/src/DjangoBlog-master/.coveragerc
deleted file mode 100644
index 9757484..0000000
--- a/src/DjangoBlog-master/.coveragerc
+++ /dev/null
@@ -1,10 +0,0 @@
-[run]
-source = .
-include = *.py
-omit =
- *migrations*
- *tests*
- *.html
- *whoosh_cn_backend*
- *settings.py*
- *venv*
diff --git a/src/DjangoBlog-master/.dockerignore b/src/DjangoBlog-master/.dockerignore
deleted file mode 100644
index 2818c38..0000000
--- a/src/DjangoBlog-master/.dockerignore
+++ /dev/null
@@ -1,11 +0,0 @@
-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/src/DjangoBlog-master/.gitattributes b/src/DjangoBlog-master/.gitattributes
deleted file mode 100644
index fd52ece..0000000
--- a/src/DjangoBlog-master/.gitattributes
+++ /dev/null
@@ -1,6 +0,0 @@
-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/src/DjangoBlog-master/.github/ISSUE_TEMPLATE.md b/src/DjangoBlog-master/.github/ISSUE_TEMPLATE.md
deleted file mode 100644
index 2b5b7aa..0000000
--- a/src/DjangoBlog-master/.github/ISSUE_TEMPLATE.md
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-**我确定我已经查看了** (标注`[ ]`为`[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/src/DjangoBlog-master/.github/workflows/codeql-analysis.yml b/src/DjangoBlog-master/.github/workflows/codeql-analysis.yml
deleted file mode 100644
index 6b76522..0000000
--- a/src/DjangoBlog-master/.github/workflows/codeql-analysis.yml
+++ /dev/null
@@ -1,47 +0,0 @@
-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/src/DjangoBlog-master/.github/workflows/django.yml b/src/DjangoBlog-master/.github/workflows/django.yml
deleted file mode 100644
index 94baea9..0000000
--- a/src/DjangoBlog-master/.github/workflows/django.yml
+++ /dev/null
@@ -1,136 +0,0 @@
-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/src/DjangoBlog-master/.github/workflows/docker.yml b/src/DjangoBlog-master/.github/workflows/docker.yml
deleted file mode 100644
index a312e2f..0000000
--- a/src/DjangoBlog-master/.github/workflows/docker.yml
+++ /dev/null
@@ -1,43 +0,0 @@
-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/src/DjangoBlog-master/.github/workflows/publish-release.yml b/src/DjangoBlog-master/.github/workflows/publish-release.yml
deleted file mode 100644
index 5eb0853..0000000
--- a/src/DjangoBlog-master/.github/workflows/publish-release.yml
+++ /dev/null
@@ -1,39 +0,0 @@
-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/src/DjangoBlog-master/.gitignore b/src/DjangoBlog-master/.gitignore
deleted file mode 100644
index 3015816..0000000
--- a/src/DjangoBlog-master/.gitignore
+++ /dev/null
@@ -1,80 +0,0 @@
-# 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/src/DjangoBlog-master/Dockerfile b/src/DjangoBlog-master/Dockerfile
deleted file mode 100644
index 80b46ac..0000000
--- a/src/DjangoBlog-master/Dockerfile
+++ /dev/null
@@ -1,15 +0,0 @@
-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/src/DjangoBlog-master/LICENSE b/src/DjangoBlog-master/LICENSE
deleted file mode 100644
index 3b08474..0000000
--- a/src/DjangoBlog-master/LICENSE
+++ /dev/null
@@ -1,20 +0,0 @@
-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/src/DjangoBlog-master/README.md b/src/DjangoBlog-master/README.md
deleted file mode 100644
index 56aa4cc..0000000
--- a/src/DjangoBlog-master/README.md
+++ /dev/null
@@ -1,158 +0,0 @@
-# DjangoBlog
-
-
-
-
-
-
-
-
-
- 一款功能强大、设计优雅的现代化博客系统
-
- 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** 为本项目提供的免费开源许可证。
-
-
-
-
-
-
-
----
-> 如果本项目帮助到了你,请在[这里](https://github.com/liangliangyy/DjangoBlog/issues/214)留下你的网址,让更多的人看到。您的回复将会是我继续更新维护下去的动力。
diff --git a/src/DjangoBlog-master/accounts/__init__.py b/src/DjangoBlog-master/accounts/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/src/DjangoBlog-master/accounts/admin.py b/src/DjangoBlog-master/accounts/admin.py
deleted file mode 100644
index 32e483c..0000000
--- a/src/DjangoBlog-master/accounts/admin.py
+++ /dev/null
@@ -1,59 +0,0 @@
-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/src/DjangoBlog-master/accounts/apps.py b/src/DjangoBlog-master/accounts/apps.py
deleted file mode 100644
index 9b3fc5a..0000000
--- a/src/DjangoBlog-master/accounts/apps.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from django.apps import AppConfig
-
-
-class AccountsConfig(AppConfig):
- name = 'accounts'
diff --git a/src/DjangoBlog-master/accounts/forms.py b/src/DjangoBlog-master/accounts/forms.py
deleted file mode 100644
index fce4137..0000000
--- a/src/DjangoBlog-master/accounts/forms.py
+++ /dev/null
@@ -1,117 +0,0 @@
-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/src/DjangoBlog-master/accounts/migrations/0001_initial.py b/src/DjangoBlog-master/accounts/migrations/0001_initial.py
deleted file mode 100644
index d2fbcab..0000000
--- a/src/DjangoBlog-master/accounts/migrations/0001_initial.py
+++ /dev/null
@@ -1,49 +0,0 @@
-# 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/src/DjangoBlog-master/accounts/migrations/0002_alter_bloguser_options_remove_bloguser_created_time_and_more.py b/src/DjangoBlog-master/accounts/migrations/0002_alter_bloguser_options_remove_bloguser_created_time_and_more.py
deleted file mode 100644
index 1a9f509..0000000
--- a/src/DjangoBlog-master/accounts/migrations/0002_alter_bloguser_options_remove_bloguser_created_time_and_more.py
+++ /dev/null
@@ -1,46 +0,0 @@
-# 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/src/DjangoBlog-master/accounts/migrations/__init__.py b/src/DjangoBlog-master/accounts/migrations/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/src/DjangoBlog-master/accounts/models.py b/src/DjangoBlog-master/accounts/models.py
deleted file mode 100644
index 3baddbb..0000000
--- a/src/DjangoBlog-master/accounts/models.py
+++ /dev/null
@@ -1,35 +0,0 @@
-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/src/DjangoBlog-master/accounts/templatetags/__init__.py b/src/DjangoBlog-master/accounts/templatetags/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/src/DjangoBlog-master/accounts/tests.py b/src/DjangoBlog-master/accounts/tests.py
deleted file mode 100644
index 6893411..0000000
--- a/src/DjangoBlog-master/accounts/tests.py
+++ /dev/null
@@ -1,207 +0,0 @@
-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/src/DjangoBlog-master/accounts/urls.py b/src/DjangoBlog-master/accounts/urls.py
deleted file mode 100644
index 107a801..0000000
--- a/src/DjangoBlog-master/accounts/urls.py
+++ /dev/null
@@ -1,28 +0,0 @@
-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/src/DjangoBlog-master/accounts/user_login_backend.py b/src/DjangoBlog-master/accounts/user_login_backend.py
deleted file mode 100644
index 73cdca1..0000000
--- a/src/DjangoBlog-master/accounts/user_login_backend.py
+++ /dev/null
@@ -1,26 +0,0 @@
-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/src/DjangoBlog-master/accounts/utils.py b/src/DjangoBlog-master/accounts/utils.py
deleted file mode 100644
index 4b94bdf..0000000
--- a/src/DjangoBlog-master/accounts/utils.py
+++ /dev/null
@@ -1,49 +0,0 @@
-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/src/DjangoBlog-master/accounts/views.py b/src/DjangoBlog-master/accounts/views.py
deleted file mode 100644
index ae67aec..0000000
--- a/src/DjangoBlog-master/accounts/views.py
+++ /dev/null
@@ -1,204 +0,0 @@
-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/src/DjangoBlog-master/blog/__init__.py b/src/DjangoBlog-master/blog/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/src/DjangoBlog-master/blog/admin.py b/src/DjangoBlog-master/blog/admin.py
deleted file mode 100644
index 46c3420..0000000
--- a/src/DjangoBlog-master/blog/admin.py
+++ /dev/null
@@ -1,112 +0,0 @@
-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/src/DjangoBlog-master/blog/apps.py b/src/DjangoBlog-master/blog/apps.py
deleted file mode 100644
index 7930587..0000000
--- a/src/DjangoBlog-master/blog/apps.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from django.apps import AppConfig
-
-
-class BlogConfig(AppConfig):
- name = 'blog'
diff --git a/src/DjangoBlog-master/blog/context_processors.py b/src/DjangoBlog-master/blog/context_processors.py
deleted file mode 100644
index 73e3088..0000000
--- a/src/DjangoBlog-master/blog/context_processors.py
+++ /dev/null
@@ -1,43 +0,0 @@
-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/src/DjangoBlog-master/blog/documents.py b/src/DjangoBlog-master/blog/documents.py
deleted file mode 100644
index 0f1db7b..0000000
--- a/src/DjangoBlog-master/blog/documents.py
+++ /dev/null
@@ -1,213 +0,0 @@
-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/src/DjangoBlog-master/blog/forms.py b/src/DjangoBlog-master/blog/forms.py
deleted file mode 100644
index 715be76..0000000
--- a/src/DjangoBlog-master/blog/forms.py
+++ /dev/null
@@ -1,19 +0,0 @@
-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/src/DjangoBlog-master/blog/management/__init__.py b/src/DjangoBlog-master/blog/management/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/src/DjangoBlog-master/blog/management/commands/__init__.py b/src/DjangoBlog-master/blog/management/commands/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/src/DjangoBlog-master/blog/management/commands/build_index.py b/src/DjangoBlog-master/blog/management/commands/build_index.py
deleted file mode 100644
index 3c4acd7..0000000
--- a/src/DjangoBlog-master/blog/management/commands/build_index.py
+++ /dev/null
@@ -1,18 +0,0 @@
-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/src/DjangoBlog-master/blog/management/commands/build_search_words.py b/src/DjangoBlog-master/blog/management/commands/build_search_words.py
deleted file mode 100644
index cfe7e0d..0000000
--- a/src/DjangoBlog-master/blog/management/commands/build_search_words.py
+++ /dev/null
@@ -1,13 +0,0 @@
-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/src/DjangoBlog-master/blog/management/commands/clear_cache.py b/src/DjangoBlog-master/blog/management/commands/clear_cache.py
deleted file mode 100644
index 0d66172..0000000
--- a/src/DjangoBlog-master/blog/management/commands/clear_cache.py
+++ /dev/null
@@ -1,11 +0,0 @@
-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/src/DjangoBlog-master/blog/management/commands/create_testdata.py b/src/DjangoBlog-master/blog/management/commands/create_testdata.py
deleted file mode 100644
index 675d2ba..0000000
--- a/src/DjangoBlog-master/blog/management/commands/create_testdata.py
+++ /dev/null
@@ -1,40 +0,0 @@
-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/src/DjangoBlog-master/blog/management/commands/ping_baidu.py b/src/DjangoBlog-master/blog/management/commands/ping_baidu.py
deleted file mode 100644
index 2c7fbdd..0000000
--- a/src/DjangoBlog-master/blog/management/commands/ping_baidu.py
+++ /dev/null
@@ -1,50 +0,0 @@
-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/src/DjangoBlog-master/blog/management/commands/sync_user_avatar.py b/src/DjangoBlog-master/blog/management/commands/sync_user_avatar.py
deleted file mode 100644
index d0f4612..0000000
--- a/src/DjangoBlog-master/blog/management/commands/sync_user_avatar.py
+++ /dev/null
@@ -1,47 +0,0 @@
-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/src/DjangoBlog-master/blog/middleware.py b/src/DjangoBlog-master/blog/middleware.py
deleted file mode 100644
index 94dd70c..0000000
--- a/src/DjangoBlog-master/blog/middleware.py
+++ /dev/null
@@ -1,42 +0,0 @@
-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/src/DjangoBlog-master/blog/migrations/0001_initial.py b/src/DjangoBlog-master/blog/migrations/0001_initial.py
deleted file mode 100644
index 3d391b6..0000000
--- a/src/DjangoBlog-master/blog/migrations/0001_initial.py
+++ /dev/null
@@ -1,137 +0,0 @@
-# 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/src/DjangoBlog-master/blog/migrations/0002_blogsettings_global_footer_and_more.py b/src/DjangoBlog-master/blog/migrations/0002_blogsettings_global_footer_and_more.py
deleted file mode 100644
index adbaa36..0000000
--- a/src/DjangoBlog-master/blog/migrations/0002_blogsettings_global_footer_and_more.py
+++ /dev/null
@@ -1,23 +0,0 @@
-# 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/src/DjangoBlog-master/blog/migrations/0003_blogsettings_comment_need_review.py b/src/DjangoBlog-master/blog/migrations/0003_blogsettings_comment_need_review.py
deleted file mode 100644
index e9f5502..0000000
--- a/src/DjangoBlog-master/blog/migrations/0003_blogsettings_comment_need_review.py
+++ /dev/null
@@ -1,17 +0,0 @@
-# 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/src/DjangoBlog-master/blog/migrations/0004_rename_analyticscode_blogsettings_analytics_code_and_more.py b/src/DjangoBlog-master/blog/migrations/0004_rename_analyticscode_blogsettings_analytics_code_and_more.py
deleted file mode 100644
index ceb1398..0000000
--- a/src/DjangoBlog-master/blog/migrations/0004_rename_analyticscode_blogsettings_analytics_code_and_more.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# 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/src/DjangoBlog-master/blog/migrations/0005_alter_article_options_alter_category_options_and_more.py b/src/DjangoBlog-master/blog/migrations/0005_alter_article_options_alter_category_options_and_more.py
deleted file mode 100644
index d08e853..0000000
--- a/src/DjangoBlog-master/blog/migrations/0005_alter_article_options_alter_category_options_and_more.py
+++ /dev/null
@@ -1,300 +0,0 @@
-# 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/src/DjangoBlog-master/blog/migrations/0006_alter_blogsettings_options.py b/src/DjangoBlog-master/blog/migrations/0006_alter_blogsettings_options.py
deleted file mode 100644
index e36feb4..0000000
--- a/src/DjangoBlog-master/blog/migrations/0006_alter_blogsettings_options.py
+++ /dev/null
@@ -1,17 +0,0 @@
-# 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/src/DjangoBlog-master/blog/migrations/__init__.py b/src/DjangoBlog-master/blog/migrations/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/src/DjangoBlog-master/blog/models.py b/src/DjangoBlog-master/blog/models.py
deleted file mode 100644
index 083788b..0000000
--- a/src/DjangoBlog-master/blog/models.py
+++ /dev/null
@@ -1,376 +0,0 @@
-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/src/DjangoBlog-master/blog/search_indexes.py b/src/DjangoBlog-master/blog/search_indexes.py
deleted file mode 100644
index 7f1dfac..0000000
--- a/src/DjangoBlog-master/blog/search_indexes.py
+++ /dev/null
@@ -1,13 +0,0 @@
-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/src/DjangoBlog-master/blog/templatetags/__init__.py b/src/DjangoBlog-master/blog/templatetags/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/src/DjangoBlog-master/blog/templatetags/blog_tags.py b/src/DjangoBlog-master/blog/templatetags/blog_tags.py
deleted file mode 100644
index d6cd5d5..0000000
--- a/src/DjangoBlog-master/blog/templatetags/blog_tags.py
+++ /dev/null
@@ -1,344 +0,0 @@
-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/src/DjangoBlog-master/blog/tests.py b/src/DjangoBlog-master/blog/tests.py
deleted file mode 100644
index ee13505..0000000
--- a/src/DjangoBlog-master/blog/tests.py
+++ /dev/null
@@ -1,232 +0,0 @@
-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/src/DjangoBlog-master/blog/urls.py b/src/DjangoBlog-master/blog/urls.py
deleted file mode 100644
index adf2703..0000000
--- a/src/DjangoBlog-master/blog/urls.py
+++ /dev/null
@@ -1,62 +0,0 @@
-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/src/DjangoBlog-master/blog/views.py b/src/DjangoBlog-master/blog/views.py
deleted file mode 100644
index d5dc7ec..0000000
--- a/src/DjangoBlog-master/blog/views.py
+++ /dev/null
@@ -1,379 +0,0 @@
-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/src/DjangoBlog-master/comments/__init__.py b/src/DjangoBlog-master/comments/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/src/DjangoBlog-master/comments/admin.py b/src/DjangoBlog-master/comments/admin.py
deleted file mode 100644
index a814f3f..0000000
--- a/src/DjangoBlog-master/comments/admin.py
+++ /dev/null
@@ -1,47 +0,0 @@
-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/src/DjangoBlog-master/comments/apps.py b/src/DjangoBlog-master/comments/apps.py
deleted file mode 100644
index ff01b77..0000000
--- a/src/DjangoBlog-master/comments/apps.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from django.apps import AppConfig
-
-
-class CommentsConfig(AppConfig):
- name = 'comments'
diff --git a/src/DjangoBlog-master/comments/forms.py b/src/DjangoBlog-master/comments/forms.py
deleted file mode 100644
index e83737d..0000000
--- a/src/DjangoBlog-master/comments/forms.py
+++ /dev/null
@@ -1,13 +0,0 @@
-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/src/DjangoBlog-master/comments/migrations/0001_initial.py b/src/DjangoBlog-master/comments/migrations/0001_initial.py
deleted file mode 100644
index 61d1e53..0000000
--- a/src/DjangoBlog-master/comments/migrations/0001_initial.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# 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/src/DjangoBlog-master/comments/migrations/0002_alter_comment_is_enable.py b/src/DjangoBlog-master/comments/migrations/0002_alter_comment_is_enable.py
deleted file mode 100644
index 17c44db..0000000
--- a/src/DjangoBlog-master/comments/migrations/0002_alter_comment_is_enable.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# 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/src/DjangoBlog-master/comments/migrations/0003_alter_comment_options_remove_comment_created_time_and_more.py b/src/DjangoBlog-master/comments/migrations/0003_alter_comment_options_remove_comment_created_time_and_more.py
deleted file mode 100644
index a1ca970..0000000
--- a/src/DjangoBlog-master/comments/migrations/0003_alter_comment_options_remove_comment_created_time_and_more.py
+++ /dev/null
@@ -1,60 +0,0 @@
-# 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/src/DjangoBlog-master/comments/migrations/__init__.py b/src/DjangoBlog-master/comments/migrations/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/src/DjangoBlog-master/comments/models.py b/src/DjangoBlog-master/comments/models.py
deleted file mode 100644
index 7c3bbc8..0000000
--- a/src/DjangoBlog-master/comments/models.py
+++ /dev/null
@@ -1,39 +0,0 @@
-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/src/DjangoBlog-master/comments/templatetags/__init__.py b/src/DjangoBlog-master/comments/templatetags/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/src/DjangoBlog-master/comments/templatetags/comments_tags.py b/src/DjangoBlog-master/comments/templatetags/comments_tags.py
deleted file mode 100644
index fde02b4..0000000
--- a/src/DjangoBlog-master/comments/templatetags/comments_tags.py
+++ /dev/null
@@ -1,30 +0,0 @@
-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/src/DjangoBlog-master/comments/tests.py b/src/DjangoBlog-master/comments/tests.py
deleted file mode 100644
index 2a7f55f..0000000
--- a/src/DjangoBlog-master/comments/tests.py
+++ /dev/null
@@ -1,109 +0,0 @@
-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/src/DjangoBlog-master/comments/urls.py b/src/DjangoBlog-master/comments/urls.py
deleted file mode 100644
index 7df3fab..0000000
--- a/src/DjangoBlog-master/comments/urls.py
+++ /dev/null
@@ -1,11 +0,0 @@
-from django.urls import path
-
-from . import views
-
-app_name = "comments"
-urlpatterns = [
- path(
- 'article//postcomment',
- views.CommentPostView.as_view(),
- name='postcomment'),
-]
diff --git a/src/DjangoBlog-master/comments/utils.py b/src/DjangoBlog-master/comments/utils.py
deleted file mode 100644
index f01dba7..0000000
--- a/src/DjangoBlog-master/comments/utils.py
+++ /dev/null
@@ -1,38 +0,0 @@
-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/src/DjangoBlog-master/comments/views.py b/src/DjangoBlog-master/comments/views.py
deleted file mode 100644
index ad9b2b9..0000000
--- a/src/DjangoBlog-master/comments/views.py
+++ /dev/null
@@ -1,63 +0,0 @@
-# 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/src/DjangoBlog-master/deploy/docker-compose/docker-compose.es.yml b/src/DjangoBlog-master/deploy/docker-compose/docker-compose.es.yml
deleted file mode 100644
index 83e35ff..0000000
--- a/src/DjangoBlog-master/deploy/docker-compose/docker-compose.es.yml
+++ /dev/null
@@ -1,48 +0,0 @@
-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/src/DjangoBlog-master/deploy/docker-compose/docker-compose.yml b/src/DjangoBlog-master/deploy/docker-compose/docker-compose.yml
deleted file mode 100644
index 9609af3..0000000
--- a/src/DjangoBlog-master/deploy/docker-compose/docker-compose.yml
+++ /dev/null
@@ -1,60 +0,0 @@
-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/src/DjangoBlog-master/deploy/entrypoint.sh b/src/DjangoBlog-master/deploy/entrypoint.sh
deleted file mode 100644
index 2fb6491..0000000
--- a/src/DjangoBlog-master/deploy/entrypoint.sh
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/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/src/DjangoBlog-master/deploy/k8s/configmap.yaml b/src/DjangoBlog-master/deploy/k8s/configmap.yaml
deleted file mode 100644
index 835d4ad..0000000
--- a/src/DjangoBlog-master/deploy/k8s/configmap.yaml
+++ /dev/null
@@ -1,119 +0,0 @@
-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/src/DjangoBlog-master/deploy/k8s/deployment.yaml b/src/DjangoBlog-master/deploy/k8s/deployment.yaml
deleted file mode 100644
index 414fdcc..0000000
--- a/src/DjangoBlog-master/deploy/k8s/deployment.yaml
+++ /dev/null
@@ -1,274 +0,0 @@
-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/src/DjangoBlog-master/deploy/k8s/gateway.yaml b/src/DjangoBlog-master/deploy/k8s/gateway.yaml
deleted file mode 100644
index a8de073..0000000
--- a/src/DjangoBlog-master/deploy/k8s/gateway.yaml
+++ /dev/null
@@ -1,17 +0,0 @@
-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/src/DjangoBlog-master/deploy/k8s/pv.yaml b/src/DjangoBlog-master/deploy/k8s/pv.yaml
deleted file mode 100644
index 874b72f..0000000
--- a/src/DjangoBlog-master/deploy/k8s/pv.yaml
+++ /dev/null
@@ -1,94 +0,0 @@
-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/src/DjangoBlog-master/deploy/k8s/pvc.yaml b/src/DjangoBlog-master/deploy/k8s/pvc.yaml
deleted file mode 100644
index ef238c5..0000000
--- a/src/DjangoBlog-master/deploy/k8s/pvc.yaml
+++ /dev/null
@@ -1,60 +0,0 @@
-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/src/DjangoBlog-master/deploy/k8s/service.yaml b/src/DjangoBlog-master/deploy/k8s/service.yaml
deleted file mode 100644
index 4ef2931..0000000
--- a/src/DjangoBlog-master/deploy/k8s/service.yaml
+++ /dev/null
@@ -1,80 +0,0 @@
-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/src/DjangoBlog-master/deploy/k8s/storageclass.yaml b/src/DjangoBlog-master/deploy/k8s/storageclass.yaml
deleted file mode 100644
index 5d5a14c..0000000
--- a/src/DjangoBlog-master/deploy/k8s/storageclass.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-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/src/DjangoBlog-master/deploy/nginx.conf b/src/DjangoBlog-master/deploy/nginx.conf
deleted file mode 100644
index 32161d8..0000000
--- a/src/DjangoBlog-master/deploy/nginx.conf
+++ /dev/null
@@ -1,50 +0,0 @@
-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/src/DjangoBlog-master/djangoblog/__init__.py b/src/DjangoBlog-master/djangoblog/__init__.py
deleted file mode 100644
index 1e205f4..0000000
--- a/src/DjangoBlog-master/djangoblog/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-default_app_config = 'djangoblog.apps.DjangoblogAppConfig'
diff --git a/src/DjangoBlog-master/djangoblog/admin_site.py b/src/DjangoBlog-master/djangoblog/admin_site.py
deleted file mode 100644
index f120405..0000000
--- a/src/DjangoBlog-master/djangoblog/admin_site.py
+++ /dev/null
@@ -1,64 +0,0 @@
-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/src/DjangoBlog-master/djangoblog/apps.py b/src/DjangoBlog-master/djangoblog/apps.py
deleted file mode 100644
index d29e318..0000000
--- a/src/DjangoBlog-master/djangoblog/apps.py
+++ /dev/null
@@ -1,11 +0,0 @@
-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/src/DjangoBlog-master/djangoblog/blog_signals.py b/src/DjangoBlog-master/djangoblog/blog_signals.py
deleted file mode 100644
index 393f441..0000000
--- a/src/DjangoBlog-master/djangoblog/blog_signals.py
+++ /dev/null
@@ -1,122 +0,0 @@
-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/src/DjangoBlog-master/djangoblog/elasticsearch_backend.py b/src/DjangoBlog-master/djangoblog/elasticsearch_backend.py
deleted file mode 100644
index 4afe498..0000000
--- a/src/DjangoBlog-master/djangoblog/elasticsearch_backend.py
+++ /dev/null
@@ -1,183 +0,0 @@
-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/src/DjangoBlog-master/djangoblog/feeds.py b/src/DjangoBlog-master/djangoblog/feeds.py
deleted file mode 100644
index 8c4e851..0000000
--- a/src/DjangoBlog-master/djangoblog/feeds.py
+++ /dev/null
@@ -1,40 +0,0 @@
-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/src/DjangoBlog-master/djangoblog/logentryadmin.py b/src/DjangoBlog-master/djangoblog/logentryadmin.py
deleted file mode 100644
index 2f6a535..0000000
--- a/src/DjangoBlog-master/djangoblog/logentryadmin.py
+++ /dev/null
@@ -1,91 +0,0 @@
-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/src/DjangoBlog-master/djangoblog/plugin_manage/base_plugin.py b/src/DjangoBlog-master/djangoblog/plugin_manage/base_plugin.py
deleted file mode 100644
index 2b4be5c..0000000
--- a/src/DjangoBlog-master/djangoblog/plugin_manage/base_plugin.py
+++ /dev/null
@@ -1,41 +0,0 @@
-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/src/DjangoBlog-master/djangoblog/plugin_manage/hook_constants.py b/src/DjangoBlog-master/djangoblog/plugin_manage/hook_constants.py
deleted file mode 100644
index 6685b7c..0000000
--- a/src/DjangoBlog-master/djangoblog/plugin_manage/hook_constants.py
+++ /dev/null
@@ -1,7 +0,0 @@
-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/src/DjangoBlog-master/djangoblog/plugin_manage/hooks.py b/src/DjangoBlog-master/djangoblog/plugin_manage/hooks.py
deleted file mode 100644
index d712540..0000000
--- a/src/DjangoBlog-master/djangoblog/plugin_manage/hooks.py
+++ /dev/null
@@ -1,44 +0,0 @@
-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/src/DjangoBlog-master/djangoblog/plugin_manage/loader.py b/src/DjangoBlog-master/djangoblog/plugin_manage/loader.py
deleted file mode 100644
index 12e824b..0000000
--- a/src/DjangoBlog-master/djangoblog/plugin_manage/loader.py
+++ /dev/null
@@ -1,19 +0,0 @@
-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/src/DjangoBlog-master/djangoblog/settings.py b/src/DjangoBlog-master/djangoblog/settings.py
deleted file mode 100644
index 8633633..0000000
--- a/src/DjangoBlog-master/djangoblog/settings.py
+++ /dev/null
@@ -1,341 +0,0 @@
-"""
-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': 'djangoblog',
- 'USER': 'root',
- 'PASSWORD': '083647',
- 'HOST': '127.0.0.1',
- 'PORT': 3306,
- }
-}
-
-# 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/src/DjangoBlog-master/djangoblog/sitemap.py b/src/DjangoBlog-master/djangoblog/sitemap.py
deleted file mode 100644
index 8b7d446..0000000
--- a/src/DjangoBlog-master/djangoblog/sitemap.py
+++ /dev/null
@@ -1,59 +0,0 @@
-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/src/DjangoBlog-master/djangoblog/spider_notify.py b/src/DjangoBlog-master/djangoblog/spider_notify.py
deleted file mode 100644
index 7b909e9..0000000
--- a/src/DjangoBlog-master/djangoblog/spider_notify.py
+++ /dev/null
@@ -1,21 +0,0 @@
-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/src/DjangoBlog-master/djangoblog/tests.py b/src/DjangoBlog-master/djangoblog/tests.py
deleted file mode 100644
index 01237d9..0000000
--- a/src/DjangoBlog-master/djangoblog/tests.py
+++ /dev/null
@@ -1,32 +0,0 @@
-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/src/DjangoBlog-master/djangoblog/urls.py b/src/DjangoBlog-master/djangoblog/urls.py
deleted file mode 100644
index 4aae58a..0000000
--- a/src/DjangoBlog-master/djangoblog/urls.py
+++ /dev/null
@@ -1,64 +0,0 @@
-"""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/src/DjangoBlog-master/djangoblog/utils.py b/src/DjangoBlog-master/djangoblog/utils.py
deleted file mode 100644
index 57f63dc..0000000
--- a/src/DjangoBlog-master/djangoblog/utils.py
+++ /dev/null
@@ -1,232 +0,0 @@
-#!/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/src/DjangoBlog-master/djangoblog/whoosh_cn_backend.py b/src/DjangoBlog-master/djangoblog/whoosh_cn_backend.py
deleted file mode 100644
index 04e3f7f..0000000
--- a/src/DjangoBlog-master/djangoblog/whoosh_cn_backend.py
+++ /dev/null
@@ -1,1044 +0,0 @@
-# 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%(tag)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/src/DjangoBlog-master/djangoblog/wsgi.py b/src/DjangoBlog-master/djangoblog/wsgi.py
deleted file mode 100644
index 2295efd..0000000
--- a/src/DjangoBlog-master/djangoblog/wsgi.py
+++ /dev/null
@@ -1,16 +0,0 @@
-"""
-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/src/DjangoBlog-master/docs/README-en.md b/src/DjangoBlog-master/docs/README-en.md
deleted file mode 100644
index 37ea069..0000000
--- a/src/DjangoBlog-master/docs/README-en.md
+++ /dev/null
@@ -1,158 +0,0 @@
-# DjangoBlog
-
-
-
-
-
-
-
-
-
- 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.
-
-
-
-
-
-
- (Left) Alipay / (Right) WeChat
-
-
-## 🙏 Acknowledgements
-
-A special thanks to **JetBrains** for providing a free open-source license for this project.
-
-
-
-
-
-
-
----
-> 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/src/DjangoBlog-master/docs/config-en.md b/src/DjangoBlog-master/docs/config-en.md
deleted file mode 100644
index b877efb..0000000
--- a/src/DjangoBlog-master/docs/config-en.md
+++ /dev/null
@@ -1,64 +0,0 @@
-# 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:
-
-
-
-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/src/DjangoBlog-master/docs/config.md b/src/DjangoBlog-master/docs/config.md
deleted file mode 100644
index 24673a3..0000000
--- a/src/DjangoBlog-master/docs/config.md
+++ /dev/null
@@ -1,58 +0,0 @@
-# 主要功能配置介绍:
-
-## 缓存:
-缓存默认使用`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用户登录的头像路径,填写绝对路径,默认是代码目录。
-## 代码高亮
-如果你发现你文章的代码没有高亮,请这样书写代码块:
-
-
-
-
-也就是说,需要在代码块开始位置加入这段代码对应的语言。
-
-## 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/src/DjangoBlog-master/docs/docker-en.md b/src/DjangoBlog-master/docs/docker-en.md
deleted file mode 100644
index 8d5d59e..0000000
--- a/src/DjangoBlog-master/docs/docker-en.md
+++ /dev/null
@@ -1,114 +0,0 @@
-# Deploying DjangoBlog with Docker
-
-
-
-
-
-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/src/DjangoBlog-master/docs/docker.md b/src/DjangoBlog-master/docs/docker.md
deleted file mode 100644
index e7c255a..0000000
--- a/src/DjangoBlog-master/docs/docker.md
+++ /dev/null
@@ -1,114 +0,0 @@
-# 使用 Docker 部署 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/src/DjangoBlog-master/docs/es.md b/src/DjangoBlog-master/docs/es.md
deleted file mode 100644
index 97226c5..0000000
--- a/src/DjangoBlog-master/docs/es.md
+++ /dev/null
@@ -1,28 +0,0 @@
-# 集成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/src/DjangoBlog-master/docs/imgs/alipay.jpg b/src/DjangoBlog-master/docs/imgs/alipay.jpg
deleted file mode 100644
index 424d70a..0000000
Binary files a/src/DjangoBlog-master/docs/imgs/alipay.jpg and /dev/null differ
diff --git a/src/DjangoBlog-master/docs/imgs/pycharm_logo.png b/src/DjangoBlog-master/docs/imgs/pycharm_logo.png
deleted file mode 100644
index 7f2a4b0..0000000
Binary files a/src/DjangoBlog-master/docs/imgs/pycharm_logo.png and /dev/null differ
diff --git a/src/DjangoBlog-master/docs/imgs/wechat.jpg b/src/DjangoBlog-master/docs/imgs/wechat.jpg
deleted file mode 100644
index 7edf525..0000000
Binary files a/src/DjangoBlog-master/docs/imgs/wechat.jpg and /dev/null differ
diff --git a/src/DjangoBlog-master/docs/k8s-en.md b/src/DjangoBlog-master/docs/k8s-en.md
deleted file mode 100644
index 20e9527..0000000
--- a/src/DjangoBlog-master/docs/k8s-en.md
+++ /dev/null
@@ -1,141 +0,0 @@
-# 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/src/DjangoBlog-master/docs/k8s.md b/src/DjangoBlog-master/docs/k8s.md
deleted file mode 100644
index 9da3c28..0000000
--- a/src/DjangoBlog-master/docs/k8s.md
+++ /dev/null
@@ -1,141 +0,0 @@
-# 使用 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/src/DjangoBlog-master/foodBlog/food_categories.json b/src/DjangoBlog-master/foodBlog/food_categories.json
deleted file mode 100644
index d254c4e..0000000
--- a/src/DjangoBlog-master/foodBlog/food_categories.json
+++ /dev/null
@@ -1,30 +0,0 @@
-[
- {
- "model": "blog.category",
- "pk": 1,
- "fields": {
- "name": "中式菜肴"
- }
- },
- {
- "model": "blog.category",
- "pk": 2,
- "fields": {
- "name": "西式美食"
- }
- },
- {
- "model": "blog.category",
- "pk": 3,
- "fields": {
- "name": "甜点烘焙"
- }
- },
- {
- "model": "blog.category",
- "pk": 4,
- "fields": {
- "name": "特色小吃"
- }
- }
-]
\ No newline at end of file
diff --git a/src/DjangoBlog-master/foodBlog/food_posts.json b/src/DjangoBlog-master/foodBlog/food_posts.json
deleted file mode 100644
index 1be99b1..0000000
--- a/src/DjangoBlog-master/foodBlog/food_posts.json
+++ /dev/null
@@ -1,55 +0,0 @@
-[
- {
- "model": "blog.Article",
- "pk": 1,
- "fields": {
- "title": "北京胡同里的炸酱面探店",
- "body": "在北京,胡同是这座城市的脉络,藏着老北京最地道的烟火气,也藏着不少令人惊艳的美食小店。这次,我就寻到了一家隐匿在胡同深处的炸酱面店,那味道,堪称老北京炸酱面的\"天花板\"。这家店位于东四附近的一条小胡同里,没有醒目的招牌,只有一块略显斑驳的木牌,上面用毛笔字写着\"老北京炸酱面\"。若不是本地朋友极力推荐,我大概率会与它擦肩而过。跟着导航七拐八绕,穿过两侧是灰墙灰瓦的狭窄胡同,耳边是自行车铃铛声、街坊邻里的谈笑声,仿佛一下子穿越回了老北京的旧时光,而那家炸酱面店,就安静地坐落在胡同中段。推开略显厚重的木门,店内空间不大,摆着几张木质方桌和长条凳,桌面上擦得干干净净。墙壁上挂着老北京的黑白照片,有胡同的全景,有孩童嬉戏的场景,还有老北京人吃炸酱面的模样,瞬间就把人拉进了充满回忆的氛围里。店里的食客不少,有附近的老街坊,也有像我一样慕名而来的游客,大家挤在一起,却丝毫不觉得拥挤,反而因为这浓浓的烟火气,多了几分亲近感。老板是位地道的北京大爷,穿着白色的厨师服,脸上总是挂着憨厚的笑容,看到新客进来,会热情地招呼:\"里面坐,炸酱面马上好!\"等了没几分钟,一碗热腾腾的炸酱面就端上了桌。先看那炸酱,盛在一个小巧的青花瓷碗里,酱色红亮,上面还点缀着星星点点的葱花。用筷子挑起一点,能看到酱里肥瘦相间的五花肉丁,颗粒饱满,大小均匀。老板说,这酱是用五花肉丁先煸炒出油,再加入黄酱和甜面酱慢慢熬制而成,期间要不断搅拌,这样才能让酱变得浓稠,而且不会糊锅。凑近闻一闻,酱香混合着肉香,直往鼻子里钻,却一点都不觉得腻。再看面条,是店家手工制作的手擀面。面条粗细均匀,色泽洁白,根根分明。用筷子夹起一筷子,能感觉到面条很有韧性,放进嘴里一尝,果然筋道弹牙,咀嚼起来充满了小麦的清香。老板告诉我,他们的面条都是当天现做的,和面时还加了适量的盐,这样能让面条更有嚼劲。炸酱面的配菜也很丰富,一小盘里装着黄瓜丝、胡萝卜丝、豆芽、青豆、心里美萝卜丝,色彩鲜艳,看着就很有食欲。这些配菜都切得很精细,黄瓜丝脆嫩,胡萝卜丝清甜,豆芽爽脆,和筋道的面条、香浓的炸酱搭配在一起,口感层次十分丰富。按照老北京的吃法,先把配菜倒进面条里,再挖上一大勺炸酱,然后用筷子快速地搅拌均匀。随着搅拌,面条被均匀地裹上了红亮的炸酱,配菜也与面条充分融合。夹起一筷子,送进嘴里,面条的筋道、炸酱的香浓、配菜的清爽,在口腔里交织碰撞,那味道,真是绝了!每一口都能感受到老北京美食的独特魅力,仿佛能尝到时光的味道。吃完一碗,意犹未尽,连碗底的酱汁都舍不得剩下,恨不得用馒头蘸着吃掉。这家藏在胡同里的炸酱面店,没有华丽的装修,没有精致的摆盘,却用最地道的味道,征服了食客的味蕾。在这里,吃的不仅是一碗炸酱面,更是老北京的烟火气,是胡同里的人情味。如果你也喜欢老北京美食,不妨来这条胡同里,寻找这家\"宝藏小店\",相信你也会和我一样,被这碗炸酱面深深吸引。",
- "pub_time": "2025-10-08 12:00:00",
- "status": "p",
- "comment_status": "o",
- "type": "a",
- "views": 0,
- "author": 1,
- "article_order": 0,
- "show_toc": false,
- "category": 1,
- "tags": [1]
- }
- },
- {
- "model": "blog.Article",
- "pk":2,
- "fields": {
- "title": "《意式餐厅里的味蕾漫游》",
- "body": "在城市喧嚣的角落,藏着一家充满意式风情的餐厅,推开那扇雕花木门,仿佛瞬间穿越到了亚平宁半岛。暖黄的灯光洒在铺着格子桌布的餐桌上,墙上挂着意大利各地的风景照,空气中弥漫着橄榄油、芝士与香草交融的香气,一场味蕾的漫游就此开启。首先上桌的是经典的意式番茄肉酱面。手工制作的意面粗细均匀,如丝绸般顺滑,裹满了浓郁的肉酱。肉酱由新鲜番茄慢炖而成,酸甜的汁水充分渗入肉质鲜嫩的牛肉末中,每一口都能感受到番茄的清新与牛肉的醇厚在舌尖碰撞,搭配帕玛森芝士碎,咸香与酸甜交织,层次丰富得让人着迷。接着是意式烤千层面,这简直是芝士爱好者的天堂。层层叠叠的面皮间,夹着细腻的牛肉馅、奶香十足的 béchamel 酱,最上层铺满了马苏里拉芝士。经烤箱烤制后,芝士呈现出诱人的焦黄色,轻轻用叉子一挑,芝士拉出长长的丝,入口即化,面皮的柔韧、馅料的鲜美与芝士的浓郁完美融合,每一层都带来不同的味觉惊喜。最后以一份提拉米苏收尾再合适不过。手指饼干浸润了咖啡酒,带着微微的苦涩,与上层绵密的马斯卡彭芝士奶油完美平衡,顶部撒的可可粉更添了一丝醇厚。用小勺挖上一口,冰凉丝滑的口感在口中散开,咖啡的苦、芝士的甜、饼干的绵,交织出意式甜品独有的浪漫与馥郁。在这家意式餐厅,每一道菜都像是一位意大利友人,用最地道的风味,诉说着亚平宁半岛的阳光与浪漫,让我在城市里,也能拥有一场酣畅淋漓的味蕾漫游。",
- "pub_time": "2025-10-08 12:00:00",
- "status": "p",
- "comment_status": "o",
- "type": "a",
- "views": 0,
- "author": 1,
- "article_order": 0,
- "show_toc": false,
- "category": 2,
- "tags": [3]
- }
- },
- {
- "model": "blog.Article",
- "pk": 3,
- "fields": {
- "title": "《法式甜品店的午后邂逅》",
- "body": "在繁华街区的转角处,一家名为『甜蜜时光』的法式甜品店静静伫立。推开那扇镶嵌着琉璃的蓝色木门,清脆的风铃声伴随着扑面而来的黄油香气,瞬间将人带入一个甜蜜的梦境。店内装饰着复古镜框与蕾丝窗帘,大理石台面上陈列着琳琅满目的甜品,每一款都如同精雕细琢的艺术品,令人目不暇接。首先品尝的是经典的拿破仑千层酥。三层金黄酥脆的派皮之间,均匀地夹着香草籽点缀的卡仕达酱。用叉子轻轻一压,酥皮应声碎裂,发出悦耳的咔嚓声。入口时,奶油的丝滑与派皮的酥脆在口中交织,香草的芬芳缓缓释放,甜而不腻,层次分明,仿佛在舌尖演奏了一首优雅的法国香颂。接下来是外形精致的覆盆子慕斯。光滑的镜面淋面下,是轻盈如云的慕斯体,中间包裹着酸甜的覆盆子果酱夹心。用小勺挖开,慕斯的绵密与果酱的流动感形成美妙对比。覆盆子的微酸恰到好处地平衡了慕斯的甜度,入口即化,余味带着一丝果香的清新,令人回味无穷。最后以一杯手冲伯爵茶搭配柠檬玛德琳收尾。现烤的玛德琳蛋糕散发着柠檬的清香,标志性的贝壳造型可爱迷人。蛋糕体湿润柔软,边缘带着微微的焦脆。轻咬一口,黄油的浓郁与柠檬的清爽相得益彰,再啜饮一口佛手柑香气萦绕的伯爵茶,茶香与蛋糕的甜味在口中完美融合,为这个午后画上了一个圆满的句号。在这家法式甜品店,每一道甜品都是一首诗,用细腻的口感与精致的造型,诉说着法式浪漫的甜蜜絮语,让我在忙碌的生活中,寻得了一份难得的惬意与治愈。",
- "pub_time": "2025-10-09 14:30:00",
- "status": "p",
- "comment_status": "o",
- "type": "a",
- "views": 0,
- "author": 1,
- "article_order": 0,
- "show_toc": false,
- "category": 3,
- "tags": [3]
- }
- }]
\ No newline at end of file
diff --git a/src/DjangoBlog-master/foodBlog/food_tags.json b/src/DjangoBlog-master/foodBlog/food_tags.json
deleted file mode 100644
index 1be99b1..0000000
--- a/src/DjangoBlog-master/foodBlog/food_tags.json
+++ /dev/null
@@ -1,55 +0,0 @@
-[
- {
- "model": "blog.Article",
- "pk": 1,
- "fields": {
- "title": "北京胡同里的炸酱面探店",
- "body": "在北京,胡同是这座城市的脉络,藏着老北京最地道的烟火气,也藏着不少令人惊艳的美食小店。这次,我就寻到了一家隐匿在胡同深处的炸酱面店,那味道,堪称老北京炸酱面的\"天花板\"。这家店位于东四附近的一条小胡同里,没有醒目的招牌,只有一块略显斑驳的木牌,上面用毛笔字写着\"老北京炸酱面\"。若不是本地朋友极力推荐,我大概率会与它擦肩而过。跟着导航七拐八绕,穿过两侧是灰墙灰瓦的狭窄胡同,耳边是自行车铃铛声、街坊邻里的谈笑声,仿佛一下子穿越回了老北京的旧时光,而那家炸酱面店,就安静地坐落在胡同中段。推开略显厚重的木门,店内空间不大,摆着几张木质方桌和长条凳,桌面上擦得干干净净。墙壁上挂着老北京的黑白照片,有胡同的全景,有孩童嬉戏的场景,还有老北京人吃炸酱面的模样,瞬间就把人拉进了充满回忆的氛围里。店里的食客不少,有附近的老街坊,也有像我一样慕名而来的游客,大家挤在一起,却丝毫不觉得拥挤,反而因为这浓浓的烟火气,多了几分亲近感。老板是位地道的北京大爷,穿着白色的厨师服,脸上总是挂着憨厚的笑容,看到新客进来,会热情地招呼:\"里面坐,炸酱面马上好!\"等了没几分钟,一碗热腾腾的炸酱面就端上了桌。先看那炸酱,盛在一个小巧的青花瓷碗里,酱色红亮,上面还点缀着星星点点的葱花。用筷子挑起一点,能看到酱里肥瘦相间的五花肉丁,颗粒饱满,大小均匀。老板说,这酱是用五花肉丁先煸炒出油,再加入黄酱和甜面酱慢慢熬制而成,期间要不断搅拌,这样才能让酱变得浓稠,而且不会糊锅。凑近闻一闻,酱香混合着肉香,直往鼻子里钻,却一点都不觉得腻。再看面条,是店家手工制作的手擀面。面条粗细均匀,色泽洁白,根根分明。用筷子夹起一筷子,能感觉到面条很有韧性,放进嘴里一尝,果然筋道弹牙,咀嚼起来充满了小麦的清香。老板告诉我,他们的面条都是当天现做的,和面时还加了适量的盐,这样能让面条更有嚼劲。炸酱面的配菜也很丰富,一小盘里装着黄瓜丝、胡萝卜丝、豆芽、青豆、心里美萝卜丝,色彩鲜艳,看着就很有食欲。这些配菜都切得很精细,黄瓜丝脆嫩,胡萝卜丝清甜,豆芽爽脆,和筋道的面条、香浓的炸酱搭配在一起,口感层次十分丰富。按照老北京的吃法,先把配菜倒进面条里,再挖上一大勺炸酱,然后用筷子快速地搅拌均匀。随着搅拌,面条被均匀地裹上了红亮的炸酱,配菜也与面条充分融合。夹起一筷子,送进嘴里,面条的筋道、炸酱的香浓、配菜的清爽,在口腔里交织碰撞,那味道,真是绝了!每一口都能感受到老北京美食的独特魅力,仿佛能尝到时光的味道。吃完一碗,意犹未尽,连碗底的酱汁都舍不得剩下,恨不得用馒头蘸着吃掉。这家藏在胡同里的炸酱面店,没有华丽的装修,没有精致的摆盘,却用最地道的味道,征服了食客的味蕾。在这里,吃的不仅是一碗炸酱面,更是老北京的烟火气,是胡同里的人情味。如果你也喜欢老北京美食,不妨来这条胡同里,寻找这家\"宝藏小店\",相信你也会和我一样,被这碗炸酱面深深吸引。",
- "pub_time": "2025-10-08 12:00:00",
- "status": "p",
- "comment_status": "o",
- "type": "a",
- "views": 0,
- "author": 1,
- "article_order": 0,
- "show_toc": false,
- "category": 1,
- "tags": [1]
- }
- },
- {
- "model": "blog.Article",
- "pk":2,
- "fields": {
- "title": "《意式餐厅里的味蕾漫游》",
- "body": "在城市喧嚣的角落,藏着一家充满意式风情的餐厅,推开那扇雕花木门,仿佛瞬间穿越到了亚平宁半岛。暖黄的灯光洒在铺着格子桌布的餐桌上,墙上挂着意大利各地的风景照,空气中弥漫着橄榄油、芝士与香草交融的香气,一场味蕾的漫游就此开启。首先上桌的是经典的意式番茄肉酱面。手工制作的意面粗细均匀,如丝绸般顺滑,裹满了浓郁的肉酱。肉酱由新鲜番茄慢炖而成,酸甜的汁水充分渗入肉质鲜嫩的牛肉末中,每一口都能感受到番茄的清新与牛肉的醇厚在舌尖碰撞,搭配帕玛森芝士碎,咸香与酸甜交织,层次丰富得让人着迷。接着是意式烤千层面,这简直是芝士爱好者的天堂。层层叠叠的面皮间,夹着细腻的牛肉馅、奶香十足的 béchamel 酱,最上层铺满了马苏里拉芝士。经烤箱烤制后,芝士呈现出诱人的焦黄色,轻轻用叉子一挑,芝士拉出长长的丝,入口即化,面皮的柔韧、馅料的鲜美与芝士的浓郁完美融合,每一层都带来不同的味觉惊喜。最后以一份提拉米苏收尾再合适不过。手指饼干浸润了咖啡酒,带着微微的苦涩,与上层绵密的马斯卡彭芝士奶油完美平衡,顶部撒的可可粉更添了一丝醇厚。用小勺挖上一口,冰凉丝滑的口感在口中散开,咖啡的苦、芝士的甜、饼干的绵,交织出意式甜品独有的浪漫与馥郁。在这家意式餐厅,每一道菜都像是一位意大利友人,用最地道的风味,诉说着亚平宁半岛的阳光与浪漫,让我在城市里,也能拥有一场酣畅淋漓的味蕾漫游。",
- "pub_time": "2025-10-08 12:00:00",
- "status": "p",
- "comment_status": "o",
- "type": "a",
- "views": 0,
- "author": 1,
- "article_order": 0,
- "show_toc": false,
- "category": 2,
- "tags": [3]
- }
- },
- {
- "model": "blog.Article",
- "pk": 3,
- "fields": {
- "title": "《法式甜品店的午后邂逅》",
- "body": "在繁华街区的转角处,一家名为『甜蜜时光』的法式甜品店静静伫立。推开那扇镶嵌着琉璃的蓝色木门,清脆的风铃声伴随着扑面而来的黄油香气,瞬间将人带入一个甜蜜的梦境。店内装饰着复古镜框与蕾丝窗帘,大理石台面上陈列着琳琅满目的甜品,每一款都如同精雕细琢的艺术品,令人目不暇接。首先品尝的是经典的拿破仑千层酥。三层金黄酥脆的派皮之间,均匀地夹着香草籽点缀的卡仕达酱。用叉子轻轻一压,酥皮应声碎裂,发出悦耳的咔嚓声。入口时,奶油的丝滑与派皮的酥脆在口中交织,香草的芬芳缓缓释放,甜而不腻,层次分明,仿佛在舌尖演奏了一首优雅的法国香颂。接下来是外形精致的覆盆子慕斯。光滑的镜面淋面下,是轻盈如云的慕斯体,中间包裹着酸甜的覆盆子果酱夹心。用小勺挖开,慕斯的绵密与果酱的流动感形成美妙对比。覆盆子的微酸恰到好处地平衡了慕斯的甜度,入口即化,余味带着一丝果香的清新,令人回味无穷。最后以一杯手冲伯爵茶搭配柠檬玛德琳收尾。现烤的玛德琳蛋糕散发着柠檬的清香,标志性的贝壳造型可爱迷人。蛋糕体湿润柔软,边缘带着微微的焦脆。轻咬一口,黄油的浓郁与柠檬的清爽相得益彰,再啜饮一口佛手柑香气萦绕的伯爵茶,茶香与蛋糕的甜味在口中完美融合,为这个午后画上了一个圆满的句号。在这家法式甜品店,每一道甜品都是一首诗,用细腻的口感与精致的造型,诉说着法式浪漫的甜蜜絮语,让我在忙碌的生活中,寻得了一份难得的惬意与治愈。",
- "pub_time": "2025-10-09 14:30:00",
- "status": "p",
- "comment_status": "o",
- "type": "a",
- "views": 0,
- "author": 1,
- "article_order": 0,
- "show_toc": false,
- "category": 3,
- "tags": [3]
- }
- }]
\ No newline at end of file
diff --git a/src/DjangoBlog-master/foodBlog/food_users.json b/src/DjangoBlog-master/foodBlog/food_users.json
deleted file mode 100644
index e017bb2..0000000
--- a/src/DjangoBlog-master/foodBlog/food_users.json
+++ /dev/null
@@ -1,13 +0,0 @@
-[
- {
- "model": "auth.user",
- "pk": 1,
- "fields": {
- "username": "zhanghui",
- "password": "083647",
- "email": "1096877868@qq.com",
- "is_staff": false,
- "is_superuser": false
- }
- }
-]
\ No newline at end of file
diff --git a/src/DjangoBlog-master/locale/en/LC_MESSAGES/django.mo b/src/DjangoBlog-master/locale/en/LC_MESSAGES/django.mo
deleted file mode 100644
index f63669f..0000000
Binary files a/src/DjangoBlog-master/locale/en/LC_MESSAGES/django.mo and /dev/null differ
diff --git a/src/DjangoBlog-master/locale/en/LC_MESSAGES/django.po b/src/DjangoBlog-master/locale/en/LC_MESSAGES/django.po
deleted file mode 100644
index c80b30a..0000000
--- a/src/DjangoBlog-master/locale/en/LC_MESSAGES/django.po
+++ /dev/null
@@ -1,685 +0,0 @@
-# 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/src/DjangoBlog-master/locale/zh_Hans/LC_MESSAGES/django.mo b/src/DjangoBlog-master/locale/zh_Hans/LC_MESSAGES/django.mo
deleted file mode 100644
index a2d36e9..0000000
Binary files a/src/DjangoBlog-master/locale/zh_Hans/LC_MESSAGES/django.mo and /dev/null differ
diff --git a/src/DjangoBlog-master/locale/zh_Hans/LC_MESSAGES/django.po b/src/DjangoBlog-master/locale/zh_Hans/LC_MESSAGES/django.po
deleted file mode 100644
index 200b7e6..0000000
--- a/src/DjangoBlog-master/locale/zh_Hans/LC_MESSAGES/django.po
+++ /dev/null
@@ -1,667 +0,0 @@
-# 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
-#| 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/src/DjangoBlog-master/locale/zh_Hant/LC_MESSAGES/django.mo b/src/DjangoBlog-master/locale/zh_Hant/LC_MESSAGES/django.mo
deleted file mode 100644
index fe2ea17..0000000
Binary files a/src/DjangoBlog-master/locale/zh_Hant/LC_MESSAGES/django.mo and /dev/null differ
diff --git a/src/DjangoBlog-master/locale/zh_Hant/LC_MESSAGES/django.po b/src/DjangoBlog-master/locale/zh_Hant/LC_MESSAGES/django.po
deleted file mode 100644
index a2920ce..0000000
--- a/src/DjangoBlog-master/locale/zh_Hant/LC_MESSAGES/django.po
+++ /dev/null
@@ -1,668 +0,0 @@
-# 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/src/DjangoBlog-master/manage.py b/src/DjangoBlog-master/manage.py
deleted file mode 100644
index 919ba74..0000000
--- a/src/DjangoBlog-master/manage.py
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/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/src/DjangoBlog-master/oauth/__init__.py b/src/DjangoBlog-master/oauth/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/src/DjangoBlog-master/oauth/admin.py b/src/DjangoBlog-master/oauth/admin.py
deleted file mode 100644
index 57eab5f..0000000
--- a/src/DjangoBlog-master/oauth/admin.py
+++ /dev/null
@@ -1,54 +0,0 @@
-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/src/DjangoBlog-master/oauth/apps.py b/src/DjangoBlog-master/oauth/apps.py
deleted file mode 100644
index 17fcea2..0000000
--- a/src/DjangoBlog-master/oauth/apps.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from django.apps import AppConfig
-
-
-class OauthConfig(AppConfig):
- name = 'oauth'
diff --git a/src/DjangoBlog-master/oauth/forms.py b/src/DjangoBlog-master/oauth/forms.py
deleted file mode 100644
index 0e4ede3..0000000
--- a/src/DjangoBlog-master/oauth/forms.py
+++ /dev/null
@@ -1,12 +0,0 @@
-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/src/DjangoBlog-master/oauth/migrations/0001_initial.py b/src/DjangoBlog-master/oauth/migrations/0001_initial.py
deleted file mode 100644
index 3aa3e03..0000000
--- a/src/DjangoBlog-master/oauth/migrations/0001_initial.py
+++ /dev/null
@@ -1,57 +0,0 @@
-# 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/src/DjangoBlog-master/oauth/migrations/0002_alter_oauthconfig_options_alter_oauthuser_options_and_more.py b/src/DjangoBlog-master/oauth/migrations/0002_alter_oauthconfig_options_alter_oauthuser_options_and_more.py
deleted file mode 100644
index d5cc70e..0000000
--- a/src/DjangoBlog-master/oauth/migrations/0002_alter_oauthconfig_options_alter_oauthuser_options_and_more.py
+++ /dev/null
@@ -1,86 +0,0 @@
-# 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/src/DjangoBlog-master/oauth/migrations/0003_alter_oauthuser_nickname.py b/src/DjangoBlog-master/oauth/migrations/0003_alter_oauthuser_nickname.py
deleted file mode 100644
index 6af08eb..0000000
--- a/src/DjangoBlog-master/oauth/migrations/0003_alter_oauthuser_nickname.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# 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/src/DjangoBlog-master/oauth/migrations/__init__.py b/src/DjangoBlog-master/oauth/migrations/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/src/DjangoBlog-master/oauth/models.py b/src/DjangoBlog-master/oauth/models.py
deleted file mode 100644
index be838ed..0000000
--- a/src/DjangoBlog-master/oauth/models.py
+++ /dev/null
@@ -1,67 +0,0 @@
-# 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/src/DjangoBlog-master/oauth/oauthmanager.py b/src/DjangoBlog-master/oauth/oauthmanager.py
deleted file mode 100644
index 2e7ceef..0000000
--- a/src/DjangoBlog-master/oauth/oauthmanager.py
+++ /dev/null
@@ -1,504 +0,0 @@
-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/src/DjangoBlog-master/oauth/templatetags/__init__.py b/src/DjangoBlog-master/oauth/templatetags/__init__.py
deleted file mode 100644
index 8b13789..0000000
--- a/src/DjangoBlog-master/oauth/templatetags/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/DjangoBlog-master/oauth/templatetags/oauth_tags.py b/src/DjangoBlog-master/oauth/templatetags/oauth_tags.py
deleted file mode 100644
index 7b687d5..0000000
--- a/src/DjangoBlog-master/oauth/templatetags/oauth_tags.py
+++ /dev/null
@@ -1,22 +0,0 @@
-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/src/DjangoBlog-master/oauth/tests.py b/src/DjangoBlog-master/oauth/tests.py
deleted file mode 100644
index bb23b9b..0000000
--- a/src/DjangoBlog-master/oauth/tests.py
+++ /dev/null
@@ -1,249 +0,0 @@
-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/src/DjangoBlog-master/oauth/urls.py b/src/DjangoBlog-master/oauth/urls.py
deleted file mode 100644
index c4a12a0..0000000
--- a/src/DjangoBlog-master/oauth/urls.py
+++ /dev/null
@@ -1,25 +0,0 @@
-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/src/DjangoBlog-master/oauth/views.py b/src/DjangoBlog-master/oauth/views.py
deleted file mode 100644
index 12e3a6e..0000000
--- a/src/DjangoBlog-master/oauth/views.py
+++ /dev/null
@@ -1,253 +0,0 @@
-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/src/DjangoBlog-master/owntracks/__init__.py b/src/DjangoBlog-master/owntracks/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/src/DjangoBlog-master/owntracks/admin.py b/src/DjangoBlog-master/owntracks/admin.py
deleted file mode 100644
index 655b535..0000000
--- a/src/DjangoBlog-master/owntracks/admin.py
+++ /dev/null
@@ -1,7 +0,0 @@
-from django.contrib import admin
-
-# Register your models here.
-
-
-class OwnTrackLogsAdmin(admin.ModelAdmin):
- pass
diff --git a/src/DjangoBlog-master/owntracks/apps.py b/src/DjangoBlog-master/owntracks/apps.py
deleted file mode 100644
index 1bc5f12..0000000
--- a/src/DjangoBlog-master/owntracks/apps.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from django.apps import AppConfig
-
-
-class OwntracksConfig(AppConfig):
- name = 'owntracks'
diff --git a/src/DjangoBlog-master/owntracks/migrations/0001_initial.py b/src/DjangoBlog-master/owntracks/migrations/0001_initial.py
deleted file mode 100644
index 9eee55c..0000000
--- a/src/DjangoBlog-master/owntracks/migrations/0001_initial.py
+++ /dev/null
@@ -1,31 +0,0 @@
-# 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/src/DjangoBlog-master/owntracks/migrations/0002_alter_owntracklog_options_and_more.py b/src/DjangoBlog-master/owntracks/migrations/0002_alter_owntracklog_options_and_more.py
deleted file mode 100644
index b4f8dec..0000000
--- a/src/DjangoBlog-master/owntracks/migrations/0002_alter_owntracklog_options_and_more.py
+++ /dev/null
@@ -1,22 +0,0 @@
-# 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/src/DjangoBlog-master/owntracks/migrations/__init__.py b/src/DjangoBlog-master/owntracks/migrations/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/src/DjangoBlog-master/owntracks/models.py b/src/DjangoBlog-master/owntracks/models.py
deleted file mode 100644
index 760942c..0000000
--- a/src/DjangoBlog-master/owntracks/models.py
+++ /dev/null
@@ -1,20 +0,0 @@
-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/src/DjangoBlog-master/owntracks/tests.py b/src/DjangoBlog-master/owntracks/tests.py
deleted file mode 100644
index 3b4b9d8..0000000
--- a/src/DjangoBlog-master/owntracks/tests.py
+++ /dev/null
@@ -1,64 +0,0 @@
-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/src/DjangoBlog-master/owntracks/urls.py b/src/DjangoBlog-master/owntracks/urls.py
deleted file mode 100644
index c19ada8..0000000
--- a/src/DjangoBlog-master/owntracks/urls.py
+++ /dev/null
@@ -1,12 +0,0 @@
-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/src/DjangoBlog-master/owntracks/views.py b/src/DjangoBlog-master/owntracks/views.py
deleted file mode 100644
index 4c72bdd..0000000
--- a/src/DjangoBlog-master/owntracks/views.py
+++ /dev/null
@@ -1,127 +0,0 @@
-# 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/src/DjangoBlog-master/plugins/__init__.py b/src/DjangoBlog-master/plugins/__init__.py
deleted file mode 100644
index e88afca..0000000
--- a/src/DjangoBlog-master/plugins/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-# This file makes this a Python package
diff --git a/src/DjangoBlog-master/plugins/article_copyright/__init__.py b/src/DjangoBlog-master/plugins/article_copyright/__init__.py
deleted file mode 100644
index e88afca..0000000
--- a/src/DjangoBlog-master/plugins/article_copyright/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-# This file makes this a Python package
diff --git a/src/DjangoBlog-master/plugins/article_copyright/plugin.py b/src/DjangoBlog-master/plugins/article_copyright/plugin.py
deleted file mode 100644
index 317fed2..0000000
--- a/src/DjangoBlog-master/plugins/article_copyright/plugin.py
+++ /dev/null
@@ -1,32 +0,0 @@
-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/src/DjangoBlog-master/plugins/external_links/__init__.py b/src/DjangoBlog-master/plugins/external_links/__init__.py
deleted file mode 100644
index e88afca..0000000
--- a/src/DjangoBlog-master/plugins/external_links/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-# This file makes this a Python package
diff --git a/src/DjangoBlog-master/plugins/external_links/plugin.py b/src/DjangoBlog-master/plugins/external_links/plugin.py
deleted file mode 100644
index 5b2ef14..0000000
--- a/src/DjangoBlog-master/plugins/external_links/plugin.py
+++ /dev/null
@@ -1,48 +0,0 @@
-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/src/DjangoBlog-master/plugins/reading_time/__init__.py b/src/DjangoBlog-master/plugins/reading_time/__init__.py
deleted file mode 100644
index e88afca..0000000
--- a/src/DjangoBlog-master/plugins/reading_time/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-# This file makes this a Python package
diff --git a/src/DjangoBlog-master/plugins/reading_time/plugin.py b/src/DjangoBlog-master/plugins/reading_time/plugin.py
deleted file mode 100644
index 35f9db1..0000000
--- a/src/DjangoBlog-master/plugins/reading_time/plugin.py
+++ /dev/null
@@ -1,43 +0,0 @@
-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/src/DjangoBlog-master/plugins/seo_optimizer/__init__.py b/src/DjangoBlog-master/plugins/seo_optimizer/__init__.py
deleted file mode 100644
index e88afca..0000000
--- a/src/DjangoBlog-master/plugins/seo_optimizer/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-# This file makes this a Python package
diff --git a/src/DjangoBlog-master/plugins/seo_optimizer/plugin.py b/src/DjangoBlog-master/plugins/seo_optimizer/plugin.py
deleted file mode 100644
index b5b19a3..0000000
--- a/src/DjangoBlog-master/plugins/seo_optimizer/plugin.py
+++ /dev/null
@@ -1,142 +0,0 @@
-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/src/DjangoBlog-master/plugins/view_count/__init__.py b/src/DjangoBlog-master/plugins/view_count/__init__.py
deleted file mode 100644
index 8804fdf..0000000
--- a/src/DjangoBlog-master/plugins/view_count/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-# This file makes this a Python package
\ No newline at end of file
diff --git a/src/DjangoBlog-master/plugins/view_count/plugin.py b/src/DjangoBlog-master/plugins/view_count/plugin.py
deleted file mode 100644
index 15e9d94..0000000
--- a/src/DjangoBlog-master/plugins/view_count/plugin.py
+++ /dev/null
@@ -1,18 +0,0 @@
-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/src/DjangoBlog-master/requirements.txt b/src/DjangoBlog-master/requirements.txt
deleted file mode 100644
index 9dc5c93..0000000
Binary files a/src/DjangoBlog-master/requirements.txt and /dev/null differ
diff --git a/src/DjangoBlog-master/servermanager/MemcacheStorage.py b/src/DjangoBlog-master/servermanager/MemcacheStorage.py
deleted file mode 100644
index 38a7990..0000000
--- a/src/DjangoBlog-master/servermanager/MemcacheStorage.py
+++ /dev/null
@@ -1,32 +0,0 @@
-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/src/DjangoBlog-master/servermanager/__init__.py b/src/DjangoBlog-master/servermanager/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/src/DjangoBlog-master/servermanager/admin.py b/src/DjangoBlog-master/servermanager/admin.py
deleted file mode 100644
index f26f4f6..0000000
--- a/src/DjangoBlog-master/servermanager/admin.py
+++ /dev/null
@@ -1,19 +0,0 @@
-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/src/DjangoBlog-master/servermanager/api/__init__.py b/src/DjangoBlog-master/servermanager/api/__init__.py
deleted file mode 100644
index 8b13789..0000000
--- a/src/DjangoBlog-master/servermanager/api/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/DjangoBlog-master/servermanager/api/blogapi.py b/src/DjangoBlog-master/servermanager/api/blogapi.py
deleted file mode 100644
index 8a4d6ac..0000000
--- a/src/DjangoBlog-master/servermanager/api/blogapi.py
+++ /dev/null
@@ -1,27 +0,0 @@
-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/src/DjangoBlog-master/servermanager/api/commonapi.py b/src/DjangoBlog-master/servermanager/api/commonapi.py
deleted file mode 100644
index 83ad9ff..0000000
--- a/src/DjangoBlog-master/servermanager/api/commonapi.py
+++ /dev/null
@@ -1,64 +0,0 @@
-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/src/DjangoBlog-master/servermanager/apps.py b/src/DjangoBlog-master/servermanager/apps.py
deleted file mode 100644
index 03cc38d..0000000
--- a/src/DjangoBlog-master/servermanager/apps.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from django.apps import AppConfig
-
-
-class ServermanagerConfig(AppConfig):
- name = 'servermanager'
diff --git a/src/DjangoBlog-master/servermanager/migrations/0001_initial.py b/src/DjangoBlog-master/servermanager/migrations/0001_initial.py
deleted file mode 100644
index bbdbf77..0000000
--- a/src/DjangoBlog-master/servermanager/migrations/0001_initial.py
+++ /dev/null
@@ -1,45 +0,0 @@
-# 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/src/DjangoBlog-master/servermanager/migrations/0002_alter_emailsendlog_options_and_more.py b/src/DjangoBlog-master/servermanager/migrations/0002_alter_emailsendlog_options_and_more.py
deleted file mode 100644
index 4858857..0000000
--- a/src/DjangoBlog-master/servermanager/migrations/0002_alter_emailsendlog_options_and_more.py
+++ /dev/null
@@ -1,32 +0,0 @@
-# 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/src/DjangoBlog-master/servermanager/migrations/__init__.py b/src/DjangoBlog-master/servermanager/migrations/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/src/DjangoBlog-master/servermanager/models.py b/src/DjangoBlog-master/servermanager/models.py
deleted file mode 100644
index 4326c65..0000000
--- a/src/DjangoBlog-master/servermanager/models.py
+++ /dev/null
@@ -1,33 +0,0 @@
-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/src/DjangoBlog-master/servermanager/robot.py b/src/DjangoBlog-master/servermanager/robot.py
deleted file mode 100644
index 7b45736..0000000
--- a/src/DjangoBlog-master/servermanager/robot.py
+++ /dev/null
@@ -1,187 +0,0 @@
-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/src/DjangoBlog-master/servermanager/tests.py b/src/DjangoBlog-master/servermanager/tests.py
deleted file mode 100644
index 22a6689..0000000
--- a/src/DjangoBlog-master/servermanager/tests.py
+++ /dev/null
@@ -1,79 +0,0 @@
-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/src/DjangoBlog-master/servermanager/urls.py b/src/DjangoBlog-master/servermanager/urls.py
deleted file mode 100644
index 8d134d2..0000000
--- a/src/DjangoBlog-master/servermanager/urls.py
+++ /dev/null
@@ -1,10 +0,0 @@
-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/src/DjangoBlog-master/servermanager/views.py b/src/DjangoBlog-master/servermanager/views.py
deleted file mode 100644
index 60f00ef..0000000
--- a/src/DjangoBlog-master/servermanager/views.py
+++ /dev/null
@@ -1 +0,0 @@
-# Create your views here.
diff --git a/src/DjangoBlog-master/templates/account/forget_password.html b/src/DjangoBlog-master/templates/account/forget_password.html
deleted file mode 100644
index 3384531..0000000
--- a/src/DjangoBlog-master/templates/account/forget_password.html
+++ /dev/null
@@ -1,30 +0,0 @@
-{% extends 'share_layout/base_account.html' %}
-{% load i18n %}
-{% load static %}
-{% block content %}
-
-{% endblock %}
\ No newline at end of file
diff --git a/src/DjangoBlog-master/templates/account/login.html b/src/DjangoBlog-master/templates/account/login.html
deleted file mode 100644
index cff8d33..0000000
--- a/src/DjangoBlog-master/templates/account/login.html
+++ /dev/null
@@ -1,46 +0,0 @@
-{% extends 'share_layout/base_account.html' %}
-{% load static %}
-{% load i18n %}
-{% block content %}
-
-{% endblock %}
\ No newline at end of file
diff --git a/src/DjangoBlog-master/templates/account/registration_form.html b/src/DjangoBlog-master/templates/account/registration_form.html
deleted file mode 100644
index 65e7549..0000000
--- a/src/DjangoBlog-master/templates/account/registration_form.html
+++ /dev/null
@@ -1,29 +0,0 @@
-{% extends 'share_layout/base_account.html' %}
-{% load static %}
-{% block content %}
-
-
-
Create Your Account
-
-
-
-
-
-
-
- Sign In
-
-
-
-{% endblock %}
\ No newline at end of file
diff --git a/src/DjangoBlog-master/templates/account/result.html b/src/DjangoBlog-master/templates/account/result.html
deleted file mode 100644
index 23c9094..0000000
--- a/src/DjangoBlog-master/templates/account/result.html
+++ /dev/null
@@ -1,27 +0,0 @@
-{% extends 'share_layout/base.html' %}
-{% load i18n %}
-{% block header %}
- {{ title }}
-{% endblock %}
-{% block content %}
-
-{% endblock %}
\ No newline at end of file
diff --git a/src/DjangoBlog-master/templates/blog/article_archives.html b/src/DjangoBlog-master/templates/blog/article_archives.html
deleted file mode 100644
index 959319e..0000000
--- a/src/DjangoBlog-master/templates/blog/article_archives.html
+++ /dev/null
@@ -1,60 +0,0 @@
-{% extends 'share_layout/base.html' %}
-{% load blog_tags %}
-{% load cache %}
-{% load i18n %}
-{% block header %}
-
- {% trans 'article archive' %} | {{ SITE_DESCRIPTION }}
-
-
-
-
-
-
-
-
-
-{% endblock %}
-{% block content %}
-
-
-
-
-
-
-
- {% 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/src/DjangoBlog-master/templates/blog/article_detail.html b/src/DjangoBlog-master/templates/blog/article_detail.html
deleted file mode 100644
index a74a0db..0000000
--- a/src/DjangoBlog-master/templates/blog/article_detail.html
+++ /dev/null
@@ -1,52 +0,0 @@
-{% extends 'share_layout/base.html' %}
-{% load blog_tags %}
-
-{% block header %}
-{% endblock %}
-{% block content %}
-
-
- {% load_article_detail article False user %}
-
- {% if article.type == 'a' %}
-
- 文章导航
- {% if next_article %}
-
- ← {{ next_article.title }}
- {% endif %}
- {% if prev_article %}
- {{ prev_article.title }} →
- {% endif %}
-
- {% 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 %}
-
- {% endif %}
- {% endif %}
-
-
-{% endblock %}
-
-{% block sidebar %}
- {% load_sidebar user "p" %}
-{% endblock %}
\ No newline at end of file
diff --git a/src/DjangoBlog-master/templates/blog/article_index.html b/src/DjangoBlog-master/templates/blog/article_index.html
deleted file mode 100644
index 0ee6150..0000000
--- a/src/DjangoBlog-master/templates/blog/article_index.html
+++ /dev/null
@@ -1,42 +0,0 @@
-{% 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 %}
-
- {% 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/src/DjangoBlog-master/templates/blog/error_page.html b/src/DjangoBlog-master/templates/blog/error_page.html
deleted file mode 100644
index d41cfb6..0000000
--- a/src/DjangoBlog-master/templates/blog/error_page.html
+++ /dev/null
@@ -1,45 +0,0 @@
-{% 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 %}
-
-
-{% endblock %}
-
-
-{% block sidebar %}
- {% load_sidebar user 'i' %}
-{% endblock %}
-
-
diff --git a/src/DjangoBlog-master/templates/blog/links_list.html b/src/DjangoBlog-master/templates/blog/links_list.html
deleted file mode 100644
index ccecbea..0000000
--- a/src/DjangoBlog-master/templates/blog/links_list.html
+++ /dev/null
@@ -1,44 +0,0 @@
-{% 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/src/DjangoBlog-master/templates/blog/tags/article_meta_info.html b/src/DjangoBlog-master/templates/blog/tags/article_meta_info.html
deleted file mode 100644
index cb6111c..0000000
--- a/src/DjangoBlog-master/templates/blog/tags/article_meta_info.html
+++ /dev/null
@@ -1,59 +0,0 @@
-{% load i18n %}
-{% load blog_tags %}
-
-
-
-
-
diff --git a/src/DjangoBlog-master/templates/blog/tags/article_pagination.html b/src/DjangoBlog-master/templates/blog/tags/article_pagination.html
deleted file mode 100644
index 95514ff..0000000
--- a/src/DjangoBlog-master/templates/blog/tags/article_pagination.html
+++ /dev/null
@@ -1,17 +0,0 @@
-{% load i18n %}
-
-
- {% trans 'article navigation' %}
-
- {% if page_obj.has_next and next_url%}
-
- {% endif %}
- {% if page_obj.has_previous and previous_url %}
-
- {% endif %}
-
\ No newline at end of file
diff --git a/src/DjangoBlog-master/templates/blog/tags/article_tag_list.html b/src/DjangoBlog-master/templates/blog/tags/article_tag_list.html
deleted file mode 100644
index c8ba474..0000000
--- a/src/DjangoBlog-master/templates/blog/tags/article_tag_list.html
+++ /dev/null
@@ -1,19 +0,0 @@
-{% load i18n %}
-{% if article_tags_list %}
-
-{% endif %}
diff --git a/src/DjangoBlog-master/templates/blog/tags/breadcrumb.html b/src/DjangoBlog-master/templates/blog/tags/breadcrumb.html
deleted file mode 100644
index 67087d5..0000000
--- a/src/DjangoBlog-master/templates/blog/tags/breadcrumb.html
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- {% for name,url in names %}
-
-
- {{ name }}
-
-
-
- {% endfor %}
-
- {{ title }}
-
-
-
-
-
diff --git a/src/DjangoBlog-master/templates/blog/tags/sidebar.html b/src/DjangoBlog-master/templates/blog/tags/sidebar.html
deleted file mode 100644
index f70544c..0000000
--- a/src/DjangoBlog-master/templates/blog/tags/sidebar.html
+++ /dev/null
@@ -1,136 +0,0 @@
-{% load blog_tags %}
-{% load i18n %}
-
diff --git a/src/DjangoBlog-master/templates/comments/tags/comment_item.html b/src/DjangoBlog-master/templates/comments/tags/comment_item.html
deleted file mode 100644
index ebb0388..0000000
--- a/src/DjangoBlog-master/templates/comments/tags/comment_item.html
+++ /dev/null
@@ -1,34 +0,0 @@
-{% load blog_tags %}
-
\ No newline at end of file
diff --git a/src/DjangoBlog-master/templates/comments/tags/comment_item_tree.html b/src/DjangoBlog-master/templates/comments/tags/comment_item_tree.html
deleted file mode 100644
index a9decd1..0000000
--- a/src/DjangoBlog-master/templates/comments/tags/comment_item_tree.html
+++ /dev/null
@@ -1,54 +0,0 @@
-{% load blog_tags %}
-
-{% 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/src/DjangoBlog-master/templates/comments/tags/comment_list.html b/src/DjangoBlog-master/templates/comments/tags/comment_list.html
deleted file mode 100644
index 4092161..0000000
--- a/src/DjangoBlog-master/templates/comments/tags/comment_list.html
+++ /dev/null
@@ -1,45 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/src/DjangoBlog-master/templates/comments/tags/post_comment.html b/src/DjangoBlog-master/templates/comments/tags/post_comment.html
deleted file mode 100644
index 3ae5a27..0000000
--- a/src/DjangoBlog-master/templates/comments/tags/post_comment.html
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
diff --git a/src/DjangoBlog-master/templates/oauth/bindsuccess.html b/src/DjangoBlog-master/templates/oauth/bindsuccess.html
deleted file mode 100644
index 4bee77c..0000000
--- a/src/DjangoBlog-master/templates/oauth/bindsuccess.html
+++ /dev/null
@@ -1,22 +0,0 @@
-{% extends 'share_layout/base.html' %}
-{% block header %}
- {{ title }}
-{% endblock %}
-{% block content %}
-
-{% endblock %}
\ No newline at end of file
diff --git a/src/DjangoBlog-master/templates/oauth/oauth_applications.html b/src/DjangoBlog-master/templates/oauth/oauth_applications.html
deleted file mode 100644
index a841ad2..0000000
--- a/src/DjangoBlog-master/templates/oauth/oauth_applications.html
+++ /dev/null
@@ -1,13 +0,0 @@
-{% load i18n %}
-
diff --git a/src/DjangoBlog-master/templates/oauth/require_email.html b/src/DjangoBlog-master/templates/oauth/require_email.html
deleted file mode 100644
index 3adef12..0000000
--- a/src/DjangoBlog-master/templates/oauth/require_email.html
+++ /dev/null
@@ -1,46 +0,0 @@
-{% extends 'share_layout/base_account.html' %}
-
-{% load static %}
-{% block content %}
-
-
-
绑定您的邮箱账号
-
-
- {% if picture %}
-
- {% else %}
-
- {% endif %}
-
-
-
-
- 登录
-
-
-
-{% endblock %}
\ No newline at end of file
diff --git a/src/DjangoBlog-master/templates/owntracks/show_log_dates.html b/src/DjangoBlog-master/templates/owntracks/show_log_dates.html
deleted file mode 100644
index 7dbba21..0000000
--- a/src/DjangoBlog-master/templates/owntracks/show_log_dates.html
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
- 记录日期
-
-
-
-
- {% for date in results %}
-
- {{ date }}
-
- {% endfor %}
-
-
-
\ No newline at end of file
diff --git a/src/DjangoBlog-master/templates/owntracks/show_maps.html b/src/DjangoBlog-master/templates/owntracks/show_maps.html
deleted file mode 100644
index 3aeda36..0000000
--- a/src/DjangoBlog-master/templates/owntracks/show_maps.html
+++ /dev/null
@@ -1,135 +0,0 @@
-
-
-
-
-
-
- 运动轨迹
-
-
-
-
-
-
-
-
-
-
-
-
- {# {% 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 %} - -
--