From 17b8048e0a92d034039d997a8ff2d447c776173a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=9F=E6=A5=A0?= <13910380238@163.com> Date: Thu, 9 Sep 2021 11:41:47 +0800 Subject: [PATCH 1/4] =?UTF-8?q?fix(account):=E8=A7=A3=E5=86=B3=E7=99=BB?= =?UTF-8?q?=E5=BD=95=E9=A1=B5=20checkbox=20=E9=80=89=E4=B8=AD=E6=97=A0?= =?UTF-8?q?=E6=95=88=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- accounts/views.py | 3 +++ blog/static/assets/img/checkmark.png | Bin 0 -> 221 bytes templates/account/login.html | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 blog/static/assets/img/checkmark.png diff --git a/accounts/views.py b/accounts/views.py index 8114d67..5f7499a 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -89,6 +89,7 @@ class LoginView(FormView): 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) @@ -115,6 +116,8 @@ class LoginView(FormView): 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: diff --git a/blog/static/assets/img/checkmark.png b/blog/static/assets/img/checkmark.png new file mode 100644 index 0000000000000000000000000000000000000000..4bd0eb350087ae1c5dedf8dfce9d24272d6db7a8 GIT binary patch literal 221 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4fjKx9jP7LeL$-D$|rhB?LhIn`< zrz{XmSTb=Z&*38p6En+u{{Q{|+S|v#(9kHqZt~J1u~=QV01lshZx0+fvtho3b7I!N zzo`X(CakVvh~#fO=oFl9W?*1+b#juy;s5o$?>AkQcH>Qx;N@~rlJFJ%ut7mhgTe~DWM4f;?+@i literal 0 HcmV?d00001 diff --git a/templates/account/login.html b/templates/account/login.html index f758b7a..0a10a60 100644 --- a/templates/account/login.html +++ b/templates/account/login.html @@ -25,7 +25,7 @@
{% comment %}Need help?{% endcomment %}
{% load oauth_tags %} From 3e88b74d2dbd734049eb3d9f79c3b63b2575d1c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=9F=E6=A5=A0?= <13910380238@163.com> Date: Tue, 14 Sep 2021 16:52:05 +0800 Subject: [PATCH 2/4] =?UTF-8?q?feat(account):=E5=AE=9E=E7=8E=B0=E5=BF=98?= =?UTF-8?q?=E8=AE=B0=E5=AF=86=E7=A0=81=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DjangoBlog/blog_signals.py | 17 ++-- accounts/email.py | 51 ++++++++++ accounts/forms.py | 85 ++++++++++++++++- accounts/tests.py | 116 +++++++++++++++++++++-- accounts/urls.py | 13 ++- accounts/views.py | 53 +++++++++-- blog/static/account/css/account.css | 9 ++ blog/static/account/js/account.js | 47 +++++++++ templates/account/forget_password.html | 29 ++++++ templates/account/login.html | 2 + templates/share_layout/base_account.html | 3 + 11 files changed, 397 insertions(+), 28 deletions(-) create mode 100644 accounts/email.py create mode 100644 blog/static/account/css/account.css create mode 100644 blog/static/account/js/account.js create mode 100644 templates/account/forget_password.html diff --git a/DjangoBlog/blog_signals.py b/DjangoBlog/blog_signals.py index 22260c9..d0cbedd 100644 --- a/DjangoBlog/blog_signals.py +++ b/DjangoBlog/blog_signals.py @@ -12,24 +12,23 @@ @file: blog_signals.py @time: 2017/8/12 上午10:18 """ -import django +import _thread +import logging + import django.dispatch from django.dispatch import receiver from django.conf import settings from django.contrib.admin.models import LogEntry -from DjangoBlog.utils import get_current_site from django.core.mail import EmailMultiAlternatives from django.db.models.signals import post_save -from django.contrib.auth.signals import user_logged_in, user_logged_out, user_login_failed +from django.contrib.auth.signals import user_logged_in, user_logged_out -from DjangoBlog.utils import cache, send_email, expire_view_cache, delete_sidebar_cache, delete_view_cache -from DjangoBlog.spider_notify import SpiderNotify from oauth.models import OAuthUser -from blog.models import Article, Category, Tag, Links, SideBar, BlogSettings from comments.models import Comment from comments.utils import send_comment_email -import _thread -import logging +from DjangoBlog.utils import get_current_site +from DjangoBlog.utils import cache, expire_view_cache, delete_sidebar_cache, delete_view_cache +from DjangoBlog.spider_notify import SpiderNotify logger = logging.getLogger(__name__) @@ -61,7 +60,7 @@ def send_email_signal_handler(sender, **kwargs): result = msg.send() log.send_result = result > 0 except Exception as e: - logger.error(e) + logger.error(f"失败邮箱号: {emailto}, {e}") log.send_result = False log.save() diff --git a/accounts/email.py b/accounts/email.py new file mode 100644 index 0000000..6b56241 --- /dev/null +++ b/accounts/email.py @@ -0,0 +1,51 @@ +import typing +import random +import string +from datetime import timedelta + +from django.core.cache import cache +from DjangoBlog.utils import send_email + +_code_ttl = timedelta(minutes=5) + + +def generate_code() -> str: + """生成随机数验证码""" + return ''.join(random.sample(string.digits, 6)) + + +def send(to_mail: str, code: str, subject: str = "邮件验证码"): + """发送重设密码验证码 + Args: + to_mail: 接受邮箱 + subject: 邮件主题 + code: 验证码 + """ + html_content = f"您正在重设密码,验证码为:{code}, 5分钟内有效,请妥善保管" + 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 "验证码错误" + + +def set_code(email: str, code: str): + """设置code""" + cache.set(email, code, _code_ttl.seconds) + + +def get_code(email: str) -> typing.Optional[str]: + """获取code""" + return cache.get(email) diff --git a/accounts/forms.py b/accounts/forms.py index 1f60cd4..5808946 100644 --- a/accounts/forms.py +++ b/accounts/forms.py @@ -12,11 +12,14 @@ @file: forms.py @time: 2016/11/20 下午3:16 """ -from django.contrib.auth.forms import AuthenticationForm, UserCreationForm +from django import forms from django.forms import widgets -from django.conf import settings -from django.contrib.auth import get_user_model from django.core.exceptions import ValidationError +from django.contrib.auth import get_user_model, password_validation +from django.contrib.auth.forms import AuthenticationForm, UserCreationForm + +from . import email +from .models import BlogUser class LoginForm(AuthenticationForm): @@ -50,3 +53,79 @@ class RegisterForm(UserCreationForm): class Meta: model = get_user_model() fields = ("username", "email") + + +class ForgetPasswordForm(forms.Form): + new_password1 = forms.CharField( + label="新密码", + widget=forms.PasswordInput( + attrs={ + "class": "form-control", + 'placeholder': "密码" + } + ), + ) + + new_password2 = forms.CharField( + label="确认密码", + widget=forms.PasswordInput( + attrs={ + "class": "form-control", + 'placeholder': "确认密码" + } + ), + ) + + email = forms.EmailField( + label='邮箱', + widget=forms.TextInput( + attrs={ + 'class': 'form-control', + 'placeholder': "邮箱" + } + ), + ) + + code = forms.CharField( + label='验证码', + widget=forms.TextInput( + attrs={ + 'class': 'form-control', + 'placeholder': "验证码" + } + ), + ) + + 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("两次密码不一致") + 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("未找到邮箱对应的用户") + return user_email + + def clean_code(self): + code = self.cleaned_data.get("code") + error = email.verify( + email=self.cleaned_data.get("email"), + code=code, + ) + if error: + raise ValidationError(error) + return code + + +class ForgetPasswordCodeForm(forms.Form): + email = forms.EmailField( + label="邮箱号" + ) diff --git a/accounts/tests.py b/accounts/tests.py index f3613ef..5fe2ef1 100644 --- a/accounts/tests.py +++ b/accounts/tests.py @@ -1,12 +1,12 @@ -from django.test import Client, RequestFactory, TestCase -from blog.models import Article, Category, Tag -from django.contrib.auth import get_user_model -from DjangoBlog.utils import delete_view_cache, delete_sidebar_cache -from accounts.models import BlogUser from django.urls import reverse -from DjangoBlog.utils import * from django.conf import settings from django.utils import timezone +from django.test import Client, RequestFactory, TestCase + +from accounts.models import BlogUser +from DjangoBlog.utils import * +from blog.models import Article, Category +from . import email # Create your tests here. @@ -15,6 +15,12 @@ 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 @@ -111,3 +117,101 @@ class AccountTest(TestCase): 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 = email.generate_code() + email.set_code(to_email, code) + email.send(to_email, code) + + err = email.verify("admin@admin.com", code) + self.assertEqual(err, None) + + err = email.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 = email.generate_code() + email.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) + self.assertFormError( + response=resp, + form="form", + field="email", + errors="未找到邮箱对应的用户" + ) + + def test_forget_password_email_code_error(self): + code = email.generate_code() + email.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) + self.assertFormError( + response=resp, + form="form", + field="code", + errors="验证码错误" + ) diff --git a/accounts/urls.py b/accounts/urls.py index a10ff00..e84123b 100644 --- a/accounts/urls.py +++ b/accounts/urls.py @@ -14,10 +14,10 @@ """ from django.conf.urls import url -from django.contrib.auth import views as auth_view from django.urls import path -from . import views + from .forms import LoginForm +from . import views app_name = "accounts" @@ -33,4 +33,11 @@ urlpatterns = [url(r'^login/$', name='logout'), path(r'account/result.html', views.account_result, - name='result')] + name='result'), + url(r'^forget_password/$', + views.ForgetPasswordView.as_view(), + name='forget_password'), + url(r'^forget_password_code/$', + views.ForgetPasswordEmailCode.as_view(), + name='forget_password_code'), + ] diff --git a/accounts/views.py b/accounts/views.py index 5f7499a..1314449 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -1,24 +1,31 @@ -from django.shortcuts import render import logging -from .forms import RegisterForm, LoginForm -from django.contrib.auth import authenticate, login, logout -# from django.views.generic.edit import FormView +import threading + +from django.http.request import HttpRequest +from django.http.response import HttpResponse +from django.shortcuts import render +from django.contrib.auth import logout from django.views.generic import FormView, RedirectView from django.contrib.auth import get_user_model from django.shortcuts import get_object_or_404 from django.http import HttpResponseRedirect, HttpResponseForbidden from django.urls import reverse -from django.contrib.auth.forms import AuthenticationForm, UserCreationForm +from django.contrib.auth.forms import AuthenticationForm from django.contrib.auth import REDIRECT_FIELD_NAME from django.views.decorators.csrf import csrf_protect from django.contrib import auth from django.views.decorators.cache import never_cache -from django.shortcuts import redirect from django.utils.decorators import method_decorator from django.views.decorators.debug import sensitive_post_parameters from django.utils.http import is_safe_url -from DjangoBlog.utils import send_email, get_sha256, get_current_site from django.conf import settings +from django.views import View +from django.contrib.auth.hashers import make_password + +from DjangoBlog.utils import send_email, get_sha256, get_current_site +from .forms import RegisterForm, LoginForm, ForgetPasswordForm, ForgetPasswordCodeForm +from . import email +from .models import BlogUser logger = logging.getLogger(__name__) @@ -166,3 +173,35 @@ def account_result(request): }) 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 = email.generate_code() + email.set_code(to_email, code) + + # 异步执行 + t = threading.Thread(target=email.send, args=(to_email, code)) + t.start() + + return HttpResponse("ok") diff --git a/blog/static/account/css/account.css b/blog/static/account/css/account.css new file mode 100644 index 0000000..7d4cec7 --- /dev/null +++ b/blog/static/account/css/account.css @@ -0,0 +1,9 @@ +.button { + border: none; + padding: 4px 80px; + text-align: center; + text-decoration: none; + display: inline-block; + font-size: 16px; + margin: 4px 2px; +} \ No newline at end of file diff --git a/blog/static/account/js/account.js b/blog/static/account/js/account.js new file mode 100644 index 0000000..f1a8771 --- /dev/null +++ b/blog/static/account/js/account.js @@ -0,0 +1,47 @@ +let wait = 60; + +function time(o) { + if (wait == 0) { + o.removeAttribute("disabled"); + o.value = "获取验证码"; + wait = 60 + return false + } else { + o.setAttribute("disabled", true); + o.value = "重新发送(" + wait + ")"; + wait--; + setTimeout(function () { + time(o) + }, + 1000) + } +} + +document.getElementById("btn").onclick = function () { + let id_email = $("#id_email") + let token = $("*[name='csrfmiddlewaretoken']").val() + let ts = this + let myErr = $("#myErr") + $.ajax( + { + url: "/forget_password_code/", + type: "POST", + data: { + "email": id_email.val(), + "csrfmiddlewaretoken": token + }, + success: function (result) { + if (result != "ok") { + myErr.remove() + id_email.after("") + return + } + myErr.remove() + time(ts) + }, + error: function (e) { + alert("发送失败,请重试") + } + } + ); +} diff --git a/templates/account/forget_password.html b/templates/account/forget_password.html new file mode 100644 index 0000000..1016c14 --- /dev/null +++ b/templates/account/forget_password.html @@ -0,0 +1,29 @@ +{% extends 'share_layout/base_account.html' %} +{% load static %} +{% block content %} +
+ + + + + +

+ Home Page + | + login page +

+ +
+{% endblock %} \ No newline at end of file diff --git a/templates/account/login.html b/templates/account/login.html index 0a10a60..1773896 100644 --- a/templates/account/login.html +++ b/templates/account/login.html @@ -37,6 +37,8 @@ Create Account | Home Page + | + 忘记密码

diff --git a/templates/share_layout/base_account.html b/templates/share_layout/base_account.html index d7160b5..c00d842 100644 --- a/templates/share_layout/base_account.html +++ b/templates/share_layout/base_account.html @@ -11,6 +11,7 @@ {{ SITE_NAME }} | {{ SITE_DESCRIPTION }} + {% load compress %} {% compress css %} @@ -41,4 +42,6 @@ + + \ No newline at end of file From d36a4ff344f3524ef359bceaeb522d96efd5b4dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=9F=E6=A5=A0?= <13910380238@163.com> Date: Fri, 10 Sep 2021 17:47:29 +0800 Subject: [PATCH 3/4] =?UTF-8?q?feat(admin):=E5=AE=9E=E7=8E=B0=E5=88=86?= =?UTF-8?q?=E7=B1=BB=E9=A1=BA=E5=BA=8F=E6=8E=A7=E5=88=B6=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- blog/admin.py | 1 + blog/models.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/blog/admin.py b/blog/admin.py index f5604bd..4b6968b 100644 --- a/blog/admin.py +++ b/blog/admin.py @@ -111,6 +111,7 @@ class TagAdmin(admin.ModelAdmin): class CategoryAdmin(admin.ModelAdmin): + list_display = ('name', 'parent_category', 'index') exclude = ('slug', 'last_mod_time', 'created_time') diff --git a/blog/models.py b/blog/models.py index 6612599..067de72 100644 --- a/blog/models.py +++ b/blog/models.py @@ -174,9 +174,10 @@ class Category(BaseModel): null=True, on_delete=models.CASCADE) slug = models.SlugField(default='no-slug', max_length=60, blank=True) + index = models.IntegerField(default=0, verbose_name="权重排序-越大越靠前") class Meta: - ordering = ['name'] + ordering = ['-index'] verbose_name = "分类" verbose_name_plural = verbose_name From eeb42e2ffd190e9a42bdc6ab7affd41727903044 Mon Sep 17 00:00:00 2001 From: liangliangyy Date: Wed, 15 Sep 2021 11:12:09 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E9=83=A8=E5=88=86=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E7=BB=93=E6=9E=84=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DjangoBlog/utils.py | 32 +++++++++++------------ accounts/forms.py | 8 +++--- accounts/tests.py | 26 +++++++++---------- accounts/{email.py => utils.py} | 10 ++----- accounts/views.py | 46 +++++++++++++++------------------ servermanager/api/__init__.py | 13 ---------- servermanager/api/blogapi.py | 17 ++---------- servermanager/api/commonapi.py | 23 ++++------------- 8 files changed, 62 insertions(+), 113 deletions(-) rename accounts/{email.py => utils.py} (83%) diff --git a/DjangoBlog/utils.py b/DjangoBlog/utils.py index 68f2806..6afd817 100644 --- a/DjangoBlog/utils.py +++ b/DjangoBlog/utils.py @@ -2,28 +2,21 @@ # encoding: utf-8 -""" -@version: ?? -@author: liangliangyy -@license: MIT Licence -@contact: liangliangyy@gmail.com -@site: https://www.lylinux.net/ -@software: PyCharm -@file: utils.py -@time: 2017/1/19 上午2:30 -""" -from django.core.cache import cache -from django.contrib.sites.models import Site +import logging +import os +import random +import string +import uuid from hashlib import sha256 + import mistune +import requests +from django.contrib.sites.models import Site +from django.core.cache import cache from mistune import escape, escape_link from pygments import highlight -from pygments.lexers import get_lexer_by_name from pygments.formatters import html -import logging -import requests -import uuid -import os +from pygments.lexers import get_lexer_by_name logger = logging.getLogger(__name__) @@ -187,6 +180,11 @@ def send_email(emailto, title, content): 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='/')) diff --git a/accounts/forms.py b/accounts/forms.py index 5808946..8e8049d 100644 --- a/accounts/forms.py +++ b/accounts/forms.py @@ -13,12 +13,12 @@ @time: 2016/11/20 下午3:16 """ from django import forms -from django.forms import widgets -from django.core.exceptions import ValidationError 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 . import email +from . import utils from .models import BlogUser @@ -116,7 +116,7 @@ class ForgetPasswordForm(forms.Form): def clean_code(self): code = self.cleaned_data.get("code") - error = email.verify( + error = utils.verify( email=self.cleaned_data.get("email"), code=code, ) diff --git a/accounts/tests.py b/accounts/tests.py index 5fe2ef1..f0e7b12 100644 --- a/accounts/tests.py +++ b/accounts/tests.py @@ -1,12 +1,12 @@ -from django.urls import reverse from django.conf import settings -from django.utils import timezone from django.test import Client, RequestFactory, TestCase +from django.urls import reverse +from django.utils import timezone -from accounts.models import BlogUser from DjangoBlog.utils import * +from accounts.models import BlogUser from blog.models import Article, Category -from . import email +from . import utils # Create your tests here. @@ -120,14 +120,14 @@ class AccountTest(TestCase): def test_verify_email_code(self): to_email = "admin@admin.com" - code = email.generate_code() - email.set_code(to_email, code) - email.send(to_email, code) + code = generate_code() + utils.set_code(to_email, code) + utils.send_verify_email(to_email, code) - err = email.verify("admin@admin.com", code) + err = utils.verify("admin@admin.com", code) self.assertEqual(err, None) - err = email.verify("admin@123.com", code) + err = utils.verify("admin@123.com", code) self.assertEqual(type(err), str) def test_forget_password_email_code_success(self): @@ -153,8 +153,8 @@ class AccountTest(TestCase): self.assertEqual(resp.content.decode("utf-8"), "错误的邮箱") def test_forget_password_email_success(self): - code = email.generate_code() - email.set_code(self.blog_user.email, code) + code = generate_code() + utils.set_code(self.blog_user.email, code) data = dict( new_password1=self.new_test, new_password2=self.new_test, @@ -195,8 +195,8 @@ class AccountTest(TestCase): ) def test_forget_password_email_code_error(self): - code = email.generate_code() - email.set_code(self.blog_user.email, code) + code = generate_code() + utils.set_code(self.blog_user.email, code) data = dict( new_password1=self.new_test, new_password2=self.new_test, diff --git a/accounts/email.py b/accounts/utils.py similarity index 83% rename from accounts/email.py rename to accounts/utils.py index 6b56241..cd5c360 100644 --- a/accounts/email.py +++ b/accounts/utils.py @@ -1,20 +1,14 @@ import typing -import random -import string from datetime import timedelta from django.core.cache import cache + from DjangoBlog.utils import send_email _code_ttl = timedelta(minutes=5) -def generate_code() -> str: - """生成随机数验证码""" - return ''.join(random.sample(string.digits, 6)) - - -def send(to_mail: str, code: str, subject: str = "邮件验证码"): +def send_verify_email(to_mail: str, code: str, subject: str = "邮件验证码"): """发送重设密码验证码 Args: to_mail: 接受邮箱 diff --git a/accounts/views.py b/accounts/views.py index 1314449..438337b 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -1,30 +1,29 @@ import logging -import threading +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 render -from django.contrib.auth import logout -from django.views.generic import FormView, RedirectView -from django.contrib.auth import get_user_model from django.shortcuts import get_object_or_404 -from django.http import HttpResponseRedirect, HttpResponseForbidden +from django.shortcuts import render from django.urls import reverse -from django.contrib.auth.forms import AuthenticationForm -from django.contrib.auth import REDIRECT_FIELD_NAME -from django.views.decorators.csrf import csrf_protect -from django.contrib import auth -from django.views.decorators.cache import never_cache from django.utils.decorators import method_decorator -from django.views.decorators.debug import sensitive_post_parameters from django.utils.http import is_safe_url -from django.conf import settings from django.views import View -from django.contrib.auth.hashers import make_password +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 +from DjangoBlog.utils import send_email, get_sha256, get_current_site, generate_code +from . import utils from .forms import RegisterForm, LoginForm, ForgetPasswordForm, ForgetPasswordCodeForm -from . import email from .models import BlogUser logger = logging.getLogger(__name__) @@ -69,7 +68,7 @@ class RegisterView(FormView): content=content) url = reverse('accounts:result') + \ - '?type=register&id=' + str(user.id) + '?type=register&id=' + str(user.id) return HttpResponseRedirect(url) else: return self.render_to_response({ @@ -136,8 +135,8 @@ class LoginView(FormView): redirect_to = self.request.POST.get(self.redirect_field_name) if not is_safe_url( - url=redirect_to, allowed_hosts=[ - self.request.get_host()]): + url=redirect_to, allowed_hosts=[ + self.request.get_host()]): redirect_to = self.success_url return redirect_to @@ -197,11 +196,8 @@ class ForgetPasswordEmailCode(View): return HttpResponse("错误的邮箱") to_email = form.cleaned_data["email"] - code = email.generate_code() - email.set_code(to_email, code) - - # 异步执行 - t = threading.Thread(target=email.send, args=(to_email, code)) - t.start() + code = generate_code() + utils.send_verify_email(to_email, code) + utils.set_code(to_email, code) return HttpResponse("ok") diff --git a/servermanager/api/__init__.py b/servermanager/api/__init__.py index 990c2c0..8b13789 100644 --- a/servermanager/api/__init__.py +++ b/servermanager/api/__init__.py @@ -1,14 +1 @@ -#!/usr/bin/env python -# encoding: utf-8 - -""" -@version: ?? -@author: liangliangyy -@license: MIT Licence -@contact: liangliangyy@gmail.com -@site: https://www.lylinux.net/ -@software: PyCharm -@file: __init__.py.py -@time: 2017/8/27 上午11:40 -""" diff --git a/servermanager/api/blogapi.py b/servermanager/api/blogapi.py index 24b3fea..9ac252b 100644 --- a/servermanager/api/blogapi.py +++ b/servermanager/api/blogapi.py @@ -1,19 +1,6 @@ -#!/usr/bin/env python -# encoding: utf-8 +from haystack.query import SearchQuerySet - -""" -@version: ?? -@author: liangliangyy -@license: MIT Licence -@contact: liangliangyy@gmail.com -@site: https://www.lylinux.net/ -@software: PyCharm -@file: blogapi.py -@time: 2017/8/27 上午11:40 -""" -from blog.models import Article, Category, Tag -from haystack.query import EmptySearchQuerySet, SearchQuerySet +from blog.models import Article, Category class BlogApi(): diff --git a/servermanager/api/commonapi.py b/servermanager/api/commonapi.py index 7669dde..56892d4 100644 --- a/servermanager/api/commonapi.py +++ b/servermanager/api/commonapi.py @@ -1,30 +1,17 @@ -#!/usr/bin/env python -# encoding: utf-8 - - -""" -@version: ?? -@author: liangliangyy -@license: MIT Licence -@contact: liangliangyy@gmail.com -@site: https://www.lylinux.net/ -@software: PyCharm -@file: commonapi.py -@time: 2017/9/2 上午1:43 -""" -import requests import json import logging +import requests + logger = logging.getLogger(__name__) -class TuLing(): +class TuLing: def __init__(self): self.__key__ = '2f1446eb0321804291b0a1e217c25bb5' self.__appid__ = 137762 - def __build_req_url(self, content): + def _build_req_url(self, content): return 'http://www.tuling123.com/openapi/api?key=%s&info=%s&userid=%s' % ( self.__key__, content, self.__appid__) @@ -34,7 +21,7 @@ class TuLing(): def getdata(self, content): try: - requrl = self.__build_req_url(content) + requrl = self._build_req_url(content) res = self.UserAgent(requrl).decode('utf-8') jsons = json.loads(res, encoding='utf-8')