Add mail module and fix reset password api
This commit is contained in:
10
account/tasks.py
Normal file
10
account/tasks.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from celery import shared_task
|
||||||
|
from utils.mail import send_email
|
||||||
|
|
||||||
|
|
||||||
|
@shared_task
|
||||||
|
def _send_email(from_name, to_email, to_name, subject, content):
|
||||||
|
send_email(from_name, to_email, to_name, subject, content)
|
||||||
78
account/templates/reset_password_email.html
Normal file
78
account/templates/reset_password_email.html
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
<table cellpadding="0" cellspacing="0" align="center" style="text-align:left;font-family:'微软雅黑','黑体',arial;"
|
||||||
|
width="742">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<table cellpadding="0" cellspacing="0"
|
||||||
|
style="text-align:left;border:1px solid #50a5e6;color:#fff;font-size:18px;" width="740">
|
||||||
|
<tbody>
|
||||||
|
<tr height="39" style="background-color:#50a5e6;">
|
||||||
|
<td style="padding-left:15px;font-family:'微软雅黑','黑体',arial;">
|
||||||
|
{{ website_name }} 登录信息找回
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<table cellpadding="0" cellspacing="0"
|
||||||
|
style="text-align:left;border:1px solid #f0f0f0;border-top:none;color:#585858;background-color:#fafafa;"
|
||||||
|
width="740">
|
||||||
|
<tbody>
|
||||||
|
<tr height="25">
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr height="40">
|
||||||
|
<td style="padding-left:25px;padding-right:25px;font-size:18px;font-family:'微软雅黑','黑体',arial;">
|
||||||
|
Hello, {{ username }}:
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr height="15">
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
<tr height="30">
|
||||||
|
<td style="padding-left:55px;padding-right:55px;font-family:'微软雅黑','黑体',arial;font-size:14px;">
|
||||||
|
您刚刚在 {{ website_name }} 申请了找回登录信息服务。
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr height="30">
|
||||||
|
<td style="padding-left:55px;padding-right:55px;font-family:'微软雅黑','黑体',arial;font-size:14px;">
|
||||||
|
请在<span style="color:rgb(255,0,0)">30分钟</span>内点击下面链接设置您的新密码:
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr height="60">
|
||||||
|
<td style="padding-left:55px;padding-right:55px;font-family:'微软雅黑','黑体',arial;font-size:14px;">
|
||||||
|
<a href="{{ link }}" target="_blank"
|
||||||
|
style="color: rgb(255,255,255);text-decoration: none;display: block;min-height: 39px;width: 158px;line-height: 39px;background-color:rgb(80,165,230);font-size:20px;text-align:center;">重置密码</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr height="10">
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
<tr height="20">
|
||||||
|
<td style="padding-left:55px;padding-right:55px;font-family:'微软雅黑','黑体',arial;font-size:12px;">
|
||||||
|
如果上面的链接点击无效,请复制以下链接至浏览器的地址栏直接打开。
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr height="30">
|
||||||
|
<td style="padding-left:55px;padding-right:65px;font-family:'微软雅黑','黑体',arial;">
|
||||||
|
<a href="{{ link }}" target="_blank" style="color:#0c94de;font-size:12px;">
|
||||||
|
{{ link }}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr height="20">
|
||||||
|
<td style="padding-left:55px;padding-right:55px;font-family:'微软雅黑','黑体',arial;font-size:12px;">
|
||||||
|
如果您没有提出过该申请,请忽略此邮件。有可能是其他用户误填了您的邮件地址,我们不会对你的帐户进行任何修改。
|
||||||
|
请不要向他人透露本邮件的内容,否则可能会导致您的账号被盗。
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr height="20">
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
@@ -1,14 +1,18 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
from django.contrib import auth
|
from django.contrib import auth
|
||||||
|
from django.conf import settings
|
||||||
from django.core.exceptions import MultipleObjectsReturned
|
from django.core.exceptions import MultipleObjectsReturned
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
from otpauth import OtpAuth
|
from otpauth import OtpAuth
|
||||||
|
|
||||||
|
from conf.models import WebsiteConfig
|
||||||
from utils.api import APIView, validate_serializer
|
from utils.api import APIView, validate_serializer
|
||||||
from utils.captcha import Captcha
|
from utils.captcha import Captcha
|
||||||
from utils.shortcuts import rand_str
|
from utils.shortcuts import rand_str
|
||||||
@@ -18,6 +22,7 @@ from ..models import User, UserProfile
|
|||||||
from ..serializers import (UserChangePasswordSerializer, UserLoginSerializer,
|
from ..serializers import (UserChangePasswordSerializer, UserLoginSerializer,
|
||||||
UserRegisterSerializer,
|
UserRegisterSerializer,
|
||||||
ApplyResetPasswordSerializer)
|
ApplyResetPasswordSerializer)
|
||||||
|
from ..tasks import _send_email
|
||||||
|
|
||||||
|
|
||||||
class UserLoginAPI(APIView):
|
class UserLoginAPI(APIView):
|
||||||
@@ -114,14 +119,24 @@ class ApplyResetPasswordAPI(APIView):
|
|||||||
except User.DoesNotExist:
|
except User.DoesNotExist:
|
||||||
return self.error(_("User does not exist"))
|
return self.error(_("User does not exist"))
|
||||||
if user.reset_password_token_expire_time and 0 < (
|
if user.reset_password_token_expire_time and 0 < (
|
||||||
user.reset_password_token_expire_time - now()).total_seconds() < 20 * 60:
|
user.reset_password_token_expire_time - now()).total_seconds() < 20 * 60:
|
||||||
return self.error(_("You can only reset password once per 20 minutes"))
|
return self.error(_("You can only reset password once per 20 minutes"))
|
||||||
user.reset_password_token = rand_str()
|
user.reset_password_token = rand_str()
|
||||||
|
|
||||||
user.reset_password_token_expire_time = now() + timedelta(minutes=20)
|
user.reset_password_token_expire_time = now() + timedelta(minutes=20)
|
||||||
user.save()
|
user.save()
|
||||||
# TODO:email template
|
email_template = open("reset_password_email.html", "w",
|
||||||
# TODO:send email
|
encoding="utf-8").read()
|
||||||
|
email_template = email_template.replace("{{ username }}", user.username). \
|
||||||
|
replace("{{ website_name }}", settings.WEBSITE_INFO["website_name"]). \
|
||||||
|
replace("{{ link }}", settings.WEBSITE_INFO["url"] + "/reset_password/t/" +
|
||||||
|
user.reset_password_token)
|
||||||
|
config = WebsiteConfig.objects.first()
|
||||||
|
_send_email.delay(config.name,
|
||||||
|
user.email,
|
||||||
|
user.username,
|
||||||
|
config.name + " 登录信息找回邮件",
|
||||||
|
email_template)
|
||||||
return self.success(_("Succeeded"))
|
return self.success(_("Succeeded"))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,3 +4,5 @@ dateutil
|
|||||||
otpauth
|
otpauth
|
||||||
pillow
|
pillow
|
||||||
python-dateutil
|
python-dateutil
|
||||||
|
celery
|
||||||
|
Envelopes
|
||||||
0
reset_password_email.html
Normal file
0
reset_password_email.html
Normal file
21
utils/mail.py
Normal file
21
utils/mail.py
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from envelopes import Envelope
|
||||||
|
|
||||||
|
from conf.models import SMTPConfig
|
||||||
|
|
||||||
|
|
||||||
|
def send_email(from_name, to_email, to_name, subject, content):
|
||||||
|
smtp = SMTPConfig.objects.first()
|
||||||
|
if not smtp:
|
||||||
|
return
|
||||||
|
envlope = Envelope(from_addr=(smtp.email, from_name),
|
||||||
|
to_addr=(to_email, to_name),
|
||||||
|
subject=subject,
|
||||||
|
html_body=content)
|
||||||
|
envlope.send(smtp.server,
|
||||||
|
login=smtp.email,
|
||||||
|
password=smtp.password,
|
||||||
|
port=smtp.port,
|
||||||
|
tls=smtp.tls)
|
||||||
Reference in New Issue
Block a user