diff --git a/apps/common/templates/common/flash_message_standalone.html b/apps/common/templates/common/flash_message_standalone.html
new file mode 100644
index 000000000..48cf972c4
--- /dev/null
+++ b/apps/common/templates/common/flash_message_standalone.html
@@ -0,0 +1,60 @@
+{% load static %}
+
+
+
+
+
@@ -58,7 +53,7 @@
-
+
Forgot password?
diff --git a/apps/users/templates/users/reset_password.html b/apps/users/templates/users/reset_password.html
new file mode 100644
index 000000000..b8794ade4
--- /dev/null
+++ b/apps/users/templates/users/reset_password.html
@@ -0,0 +1,87 @@
+{% load static %}
+
+
+
+
+
+
+
JumpServer
+
+ {% include '_head_css_js.html' %}
+
+
+
+
+
+
+
+
+
+
+
+
+
欢迎使用Jumpserver开源跳板机
+
+
+ Jumpserver是一款使用Python, Django开发的开源跳板机系统, 助力互联网企业高效 用户、资产、权限、审计 管理
+
+
+
+ 我们自五湖四海,我们对开源精神无比敬仰和崇拜,我们对完美、整洁、优雅 无止境的追求
+
+
+
+ 专注自动化运维,努力打造 易用、稳定、安全、自动化 的跳板机, 这是我们的不懈的追求和动力
+
+
+
+ 永远年轻,永远热泪盈眶 stay foolish stay hungry
+
+
+
+
+
+
重设密码
+
+
+{# Inspinia we app framework base on Bootstrap 3 © 2014#}
+
+
+
+
+
+
+
+ Copyright Jumpserver.org
+
+
+ © 2014-2016
+
+
+
+
+
+
+
+
diff --git a/apps/users/templates/users/reset_password_success.html.bak b/apps/users/templates/users/reset_password_success.html.bak
new file mode 100644
index 000000000..bf7961710
--- /dev/null
+++ b/apps/users/templates/users/reset_password_success.html.bak
@@ -0,0 +1,53 @@
+{% load static %}
+
+
+
+
+
+
+
+
+
{{ title }}
+
+ {% include '_head_css_js.html' %}
+
+
+
+
+
+
+
+
+
+
+
+

+
Jumpserver
+
+
+
+ 密码重置成功, 请返回登录页面登录系统 .
+
+
+
+
+
+
+
+
+
+ Copyright Jumpserver.org
+
+
+ © 2014-2016
+
+
+
+
+
+
+
diff --git a/apps/users/urls.py b/apps/users/urls.py
index 776ae1e89..d12a27528 100644
--- a/apps/users/urls.py
+++ b/apps/users/urls.py
@@ -10,7 +10,10 @@ urlpatterns = [
url(r'^login$', auth_views.login, {'template_name': 'users/login.html'}, name='login'),
url(r'^logout$', auth_views.logout, {'template_name': 'users/login.html'}, name='logout'),
url(r'^password/forget$', views.UserForgetPasswordView.as_view(), name='forget-password'),
- url(r'^password/reset$', views.UserRestPasswordView.as_view(), name='reset-password'),
+ url(r'^password/forget/sendmail-success$',
+ views.UserForgetPasswordSendmailSuccessView.as_view(), name='forget-password-sendmail-success'),
+ url(r'^password/reset$', views.UserResetPasswordView.as_view(), name='reset-password'),
+ url(r'^password/reset/success$', views.UserResetPasswordSuccessView.as_view(), name='reset-password-success'),
url(r'^users$', views.UserListView.as_view(), name='user-list'),
url(r'^users/(?P
[0-9]+)$', views.UserDetailView.as_view(), name='user-detail'),
url(r'^users/add$', views.UserAddView.as_view(), name='user-add'),
diff --git a/apps/users/utils.py b/apps/users/utils.py
index 99afd2c86..45a464703 100644
--- a/apps/users/utils.py
+++ b/apps/users/utils.py
@@ -84,7 +84,38 @@ def user_add_success_next(user):
""" % {
'name': user.name,
'rest_password_url': reverse('users:reset-password', external=True),
- 'rest_password_token': User.generate_reset_token(user.email),
+ 'rest_password_token': user.generate_reset_token(),
+ 'forget_password_url': reverse('users:forget-password', external=True),
+ 'email': user.email,
+ 'login_url': reverse('users:login', external=True),
+ }
+
+ send_mail_async.delay(subject, message, recipient_list, html_message=message)
+
+
+def send_reset_password_mail(user):
+ subject = '重设密码'
+ recipient_list = [user.email]
+ message = """
+ 您好 %(name)s:
+
+ 您好,请点击下面链接重置密码, 如果不是您申请的, 请关注账号安全
+
+ 请点击这里设置密码
+
+ 这个链接有效期1小时, 超过时间您可以 重新申请
+
+
+ ---
+
+
+ 直接登录
+
+
+ """ % {
+ 'name': user.name,
+ 'rest_password_url': reverse('users:reset-password', external=True),
+ 'rest_password_token': user.generate_reset_token(),
'forget_password_url': reverse('users:forget-password', external=True),
'email': user.email,
'login_url': reverse('users:login', external=True),
diff --git a/apps/users/views.py b/apps/users/views.py
index 833563eec..f79b9509d 100644
--- a/apps/users/views.py
+++ b/apps/users/views.py
@@ -4,20 +4,23 @@ from __future__ import unicode_literals
import logging
-from django.shortcuts import get_object_or_404, reverse, render
+from django.shortcuts import get_object_or_404, reverse, render, Http404
from django.http import HttpResponseRedirect
from django.urls import reverse_lazy
from django.db.models import Q
-from django.views.generic.base import View
+from django.views.generic.base import View, TemplateView
from django.views.generic.list import ListView
from django.views.generic.edit import CreateView, DeleteView, UpdateView, ProcessFormView, FormView
from django.views.generic.detail import DetailView
from django.contrib.messages.views import SuccessMessageMixin
from django.conf import settings
+from django.http import HttpResponseRedirect
+
+from common.utils import get_object_or_none
from .models import User, UserGroup
from .forms import UserAddForm, UserUpdateForm, UserGroupForm, UserLoginForm
-from .utils import AdminUserRequiredMixin, ssh_key_gen, user_add_success_next
+from .utils import AdminUserRequiredMixin, ssh_key_gen, user_add_success_next, send_reset_password_mail
logger = logging.getLogger('jumpserver.users.views')
@@ -179,9 +182,58 @@ class UserGroupDeleteView(DeleteView):
pass
-class UserForgetPasswordView(View):
- pass
+class UserForgetPasswordView(TemplateView):
+ template_name = 'users/forget_password.html'
+
+ def post(self, request, *args, **kwargs):
+ email = request.POST.get('email')
+ print(email)
+ user = get_object_or_none(User, email=email)
+ if not user:
+ return self.get(request, errors='邮件地址错误,请重新输入')
+ else:
+ send_reset_password_mail(user)
+ return HttpResponseRedirect(reverse('users:forget-password-sendmail-success'))
-class UserRestPasswordView(View):
- pass
+class UserForgetPasswordSendmailSuccessView(TemplateView):
+ template_name = 'common/flash_message_standalone.html'
+
+ def get_context_data(self, **kwargs):
+ context = {
+ 'title': '发送重置邮件',
+ 'messages': '发送重置邮件成功, 请登录邮箱查看, 按照提示操作 (如果没收到,请等待3-5分钟)',
+ 'redirect_url': reverse('users:login'),
+ }
+ kwargs.update(context)
+ return super(UserForgetPasswordSendmailSuccessView, self).get_context_data(**kwargs)
+
+
+class UserResetPasswordSuccessView(TemplateView):
+ template_name = 'common/flash_message_standalone.html'
+
+ def get_context_data(self, **kwargs):
+ context = {
+ 'title': '重设密码成功',
+ 'messages': '密码重置成功, 请返回登录页面登录系统',
+ 'redirect_url': reverse('users:login'),
+ }
+ kwargs.update(context)
+ return super(UserResetPasswordSuccessView, self).get_context_data(**kwargs)
+
+
+class UserResetPasswordView(TemplateView):
+ template_name = 'users/reset_password.html'
+
+ def post(self, request, *args, **kwargs):
+ password = request.POST.get('password')
+ password_confirm = request.POST.get('password-confirm')
+ token = request.GET.get('token')
+
+ if password != password_confirm:
+ return self.get(request, errors='两次密码不匹配')
+
+ if not User.reset_password(token, password):
+ return self.get(request, errors='Token不正确或已过期')
+
+ return HttpResponseRedirect(reverse('users:reset-password-success'))
diff --git a/run_server.py b/run_server.py
new file mode 100644
index 000000000..6c69fea05
--- /dev/null
+++ b/run_server.py
@@ -0,0 +1,8 @@
+#!/usr/bin/env python
+#
+
+import threading
+
+
+
+