Merge branch 'dev' into new-arch
* dev: mail 拆分模块 修改错误提示措辞 精简重置密码邮件模板 添加重置密码以后的跳转到登录页面 如果比赛已经开始,就不再显示之前测试题目的提交 admin 添加和编辑比赛页面增加提示 修改一些细节问题 添加重置密码页面和js 修改申请重置密码页面及js名称 添加重置密码api url,调整url 修改申请找回用户登录信息的api逻辑,没有用户名也可申请 添加找回用户信息功能,修改邮件模板的一些细节 去掉申请重置密码的服务中要求填写用户名,因为有很多用户不记得用户名了 添加重置密码页面的url,并在用户登录页面添加url 添加重置密码页面的url 修改检测邮箱api使其可以被重置密码页面使用 update read 增加访问首页的参数 修改首页样式;增加背景图片 Conflicts: oj/settings.py
This commit is contained in:
@@ -8,9 +8,10 @@ demo: https://qduoj.com
|
||||
|
||||
TODO:
|
||||
|
||||
- 将判题服务器改为 rpc 通信
|
||||
- 重构消息队列
|
||||
- 完善测试
|
||||
- 完善小组功能
|
||||
- 后台重构
|
||||
|
||||
![oj_previewindex.png][1]
|
||||
|
||||
|
||||
@@ -50,7 +50,6 @@ class EditUserSerializer(serializers.Serializer):
|
||||
|
||||
|
||||
class ApplyResetPasswordSerializer(serializers.Serializer):
|
||||
username = serializers.CharField(max_length=30)
|
||||
email = serializers.EmailField()
|
||||
captcha = serializers.CharField(max_length=4, min_length=4)
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ from rest_framework.response import Response
|
||||
from utils.shortcuts import (serializer_invalid_response, error_response,
|
||||
success_response, error_page, paginate, rand_str)
|
||||
from utils.captcha import Captcha
|
||||
from mail.tasks import send_email
|
||||
from utils.mail import send_email
|
||||
|
||||
from .decorators import login_required
|
||||
from .models import User, UserProfile
|
||||
@@ -62,10 +62,9 @@ def index_page(request):
|
||||
if not request.user.is_authenticated():
|
||||
return render(request, "oj/index.html")
|
||||
|
||||
try:
|
||||
if request.META['HTTP_REFERER']:
|
||||
if request.META.get('HTTP_REFERER') or request.GET.get("index"):
|
||||
return render(request, "oj/index.html")
|
||||
except KeyError:
|
||||
else:
|
||||
return http.HttpResponseRedirect('/problems/')
|
||||
|
||||
|
||||
@@ -149,17 +148,27 @@ class UsernameCheckAPIView(APIView):
|
||||
class EmailCheckAPIView(APIView):
|
||||
def get(self, request):
|
||||
"""
|
||||
检测邮箱是否存在,存在返回状态码400,不存在返回200
|
||||
检测邮箱是否存在,用状态码标识结果
|
||||
---
|
||||
"""
|
||||
#这里是为了适应前端表单验证空间的要求
|
||||
reset = request.GET.get("reset", None)
|
||||
#如果reset为true说明该请求是重置密码页面发出的,要返回的状态码应正好相反
|
||||
if reset:
|
||||
existed = 200
|
||||
does_not_existed = 400
|
||||
else:
|
||||
existed = 400
|
||||
does_not_existed = 200
|
||||
|
||||
email = request.GET.get("email", None)
|
||||
if email:
|
||||
try:
|
||||
User.objects.get(email=email)
|
||||
return Response(status=400)
|
||||
return Response(status=existed)
|
||||
except Exception:
|
||||
return Response(status=200)
|
||||
return Response(status=200)
|
||||
return Response(status=does_not_existed)
|
||||
return Response(status=does_not_existed)
|
||||
|
||||
|
||||
class UserAdminAPIView(APIView):
|
||||
@@ -274,7 +283,7 @@ class ApplyResetPasswordAPIView(APIView):
|
||||
if not captcha.check(data["captcha"]):
|
||||
return error_response(u"验证码错误")
|
||||
try:
|
||||
user = User.objects.get(username=data["username"], email=data["email"])
|
||||
user = User.objects.get(email=data["email"])
|
||||
except User.DoesNotExist:
|
||||
return error_response(u"用户不存在")
|
||||
if user.reset_password_token_create_time and (now() - user.reset_password_token_create_time).total_seconds() < 20 * 60:
|
||||
@@ -286,14 +295,14 @@ class ApplyResetPasswordAPIView(APIView):
|
||||
|
||||
email_template = email_template.replace("{{ username }}", user.username).\
|
||||
replace("{{ website_name }}", settings.WEBSITE_INFO["website_name"]).\
|
||||
replace("{{ link }}", request.scheme + "://" + request.META['HTTP_HOST'] + "/reset_password/?token=" + user.reset_password_token)
|
||||
replace("{{ link }}", request.scheme + "://" + request.META['HTTP_HOST'] + "/reset_password/t/" + user.reset_password_token)
|
||||
|
||||
send_email(settings.WEBSITE_INFO["website_name"],
|
||||
user.email,
|
||||
user.username,
|
||||
settings.WEBSITE_INFO["website_name"] + u" 密码找回邮件",
|
||||
settings.WEBSITE_INFO["website_name"] + u" 登录信息找回邮件",
|
||||
email_template)
|
||||
return success_response(u"邮件发送成功")
|
||||
return success_response(u"邮件发送成功,请前往您的邮箱查收")
|
||||
else:
|
||||
return serializer_invalid_response(serializer)
|
||||
|
||||
@@ -355,3 +364,13 @@ class SSOAPIView(APIView):
|
||||
request.user.auth_token = token
|
||||
request.user.save()
|
||||
return render(request, "oj/account/sso.html", {"redirect_url": callback + "?token=" + token, "callback": callback})
|
||||
|
||||
|
||||
def reset_password_page(request, token):
|
||||
try:
|
||||
user = User.objects.get(reset_password_token=token)
|
||||
except User.DoesNotExist:
|
||||
return error_page(request, u"链接已失效")
|
||||
if (now() - user.reset_password_token_create_time).total_seconds() > 30 * 60:
|
||||
return error_page(request, u"链接已过期")
|
||||
return render(request, "oj/account/reset_password.html", {"user": user})
|
||||
|
||||
@@ -515,6 +515,10 @@ def contest_problem_submissions_list_page(request, contest_id, page=1):
|
||||
values("id", "contest_id", "problem_id", "result", "create_time",
|
||||
"accepted_answer_time", "language", "user_id").order_by("-create_time")
|
||||
|
||||
# 如果比赛已经开始,就不再显示之前测试题目的提交
|
||||
if contest.status != CONTEST_NOT_START:
|
||||
submissions = submissions.filter(create_time__gte=contest.start_time)
|
||||
|
||||
user_id = request.GET.get("user_id", None)
|
||||
if user_id:
|
||||
submissions = submissions.filter(user_id=request.GET.get("user_id"))
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
# coding=utf-8
|
||||
@@ -1 +0,0 @@
|
||||
# coding=utf-8
|
||||
@@ -1,19 +0,0 @@
|
||||
# coding=utf-8
|
||||
import os
|
||||
from envelopes import Envelope
|
||||
|
||||
SMTP_CONFIG = {"smtp_server": "smtp.mxhichina.com",
|
||||
"email": "noreply@qduoj.com",
|
||||
"password": os.environ.get("smtp_password", "111111"),
|
||||
"tls": False}
|
||||
|
||||
|
||||
def send_email(from_name, to_email, to_name, subject, content):
|
||||
envelope = Envelope(from_addr=(SMTP_CONFIG["email"], from_name),
|
||||
to_addr=(to_email, to_name),
|
||||
subject=subject,
|
||||
html_body=content)
|
||||
envelope.send(SMTP_CONFIG["smtp_server"],
|
||||
login=SMTP_CONFIG["email"],
|
||||
password=SMTP_CONFIG["password"],
|
||||
tls=SMTP_CONFIG["tls"])
|
||||
@@ -55,7 +55,6 @@ INSTALLED_APPS = (
|
||||
'admin',
|
||||
'submission',
|
||||
'contest',
|
||||
'mail',
|
||||
'judge',
|
||||
'judge_dispatcher',
|
||||
|
||||
@@ -125,7 +124,6 @@ AUTH_USER_MODEL = 'account.User'
|
||||
|
||||
LOG_PATH = "log/"
|
||||
|
||||
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': True,
|
||||
@@ -191,9 +189,10 @@ TEST_CASE_DIR = os.path.join(BASE_DIR, 'test_case/')
|
||||
IMAGE_UPLOAD_DIR = os.path.join(BASE_DIR, 'upload/')
|
||||
|
||||
WEBSITE_INFO = {"website_name": "qduoj",
|
||||
"website_footer": u"青岛大学信息工程学院 创新实验室",
|
||||
"website_footer": u"青岛大学信息工程学院 创新实验室 <a href=\"http://www.miibeian.gov.cn/\">京ICP备15062075号-1</a>",
|
||||
"url": "https://qduoj.com"}
|
||||
|
||||
|
||||
HUEY = {
|
||||
'backend': 'huey.backends.redis_backend',
|
||||
'name': 'task_queue',
|
||||
@@ -202,3 +201,10 @@ HUEY = {
|
||||
# Options to pass into the consumer when running ``manage.py run_huey``
|
||||
'consumer_options': {'workers': 50},
|
||||
}
|
||||
|
||||
|
||||
SMTP_CONFIG = {"smtp_server": "smtp.mxhichina.com",
|
||||
"email": "noreply@qduoj.com",
|
||||
"password": os.environ.get("smtp_password", "111111"),
|
||||
"tls": False}
|
||||
|
||||
|
||||
10
oj/urls.py
10
oj/urls.py
@@ -5,7 +5,7 @@ from django.views.generic import TemplateView
|
||||
|
||||
from account.views import (UserLoginAPIView, UsernameCheckAPIView, UserRegisterAPIView,
|
||||
UserChangePasswordAPIView, EmailCheckAPIView,
|
||||
UserAdminAPIView, UserInfoAPIView,
|
||||
UserAdminAPIView, UserInfoAPIView, ResetPasswordAPIView,
|
||||
ApplyResetPasswordAPIView, SSOAPIView, UserProfileAPIView)
|
||||
|
||||
from announcement.views import AnnouncementAdminAPIView
|
||||
@@ -122,12 +122,14 @@ urlpatterns = [
|
||||
|
||||
url(r'^user/(?P<username>.+)/$', "account.views.user_index_page"),
|
||||
|
||||
url(r'^api/reset_password/$', ApplyResetPasswordAPIView.as_view(), name="apply_reset_password_api"),
|
||||
|
||||
url(r'^api/apply_reset_password/$', ApplyResetPasswordAPIView.as_view(), name="apply_reset_password_api"),
|
||||
url(r'^api/reset_password/$', ResetPasswordAPIView.as_view(), name="apply_reset_password_api"),
|
||||
url(r'^account/settings/$', TemplateView.as_view(template_name="oj/account/settings.html"), name="account_setting_page"),
|
||||
url(r'^account/settings/avatar/$', TemplateView.as_view(template_name="oj/account/avatar.html"), name="avatar_settings_page"),
|
||||
url(r'^account/sso/$', SSOAPIView.as_view(), name="sso_api"),
|
||||
url('^api/account/userprofile/$', UserProfileAPIView.as_view(), name="userprofile_api"),
|
||||
url(r'^api/account/userprofile/$', UserProfileAPIView.as_view(), name="userprofile_api"),
|
||||
url(r'^reset_password/$', TemplateView.as_view(template_name="oj/account/apply_reset_password.html"), name="apply_reset_password_page"),
|
||||
url(r'^reset_password/t/(?P<token>\w+)/$', "account.views.reset_password_page", name="reset_password_page")
|
||||
]
|
||||
|
||||
|
||||
|
||||
BIN
static/src/img/index/bg/bg0.jpg
Normal file
BIN
static/src/img/index/bg/bg0.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 MiB |
BIN
static/src/img/index/bg/bg1.jpg
Normal file
BIN
static/src/img/index/bg/bg1.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 530 KiB |
BIN
static/src/img/index/bg/bg2.jpg
Normal file
BIN
static/src/img/index/bg/bg2.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.7 MiB |
BIN
static/src/img/index/bg/bg3.jpg
Normal file
BIN
static/src/img/index/bg/bg3.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 MiB |
39
static/src/js/app/oj/account/applyResetPassword.js
Normal file
39
static/src/js/app/oj/account/applyResetPassword.js
Normal file
@@ -0,0 +1,39 @@
|
||||
require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, csrfTokenHeader) {
|
||||
var applied_captcha = false;
|
||||
$('form').validator().on('submit', function (e) {
|
||||
if (!e.isDefaultPrevented()) {
|
||||
var email = $("#email").val();
|
||||
var captcha = $("#captcha").val();
|
||||
|
||||
$.ajax({
|
||||
beforeSend: csrfTokenHeader,
|
||||
url: "/api/apply_reset_password/",
|
||||
data: {email: email, captcha: captcha},
|
||||
dataType: "json",
|
||||
method: "post",
|
||||
success: function (data) {
|
||||
if (!data.code) {
|
||||
refresh_captcha();
|
||||
bsAlert(data.data);
|
||||
}
|
||||
else {
|
||||
refresh_captcha();
|
||||
bsAlert(data.data);
|
||||
}
|
||||
},
|
||||
error: function(){
|
||||
bsAlert("额 好像出错了,请刷新页面重试。如还有问题,请填写页面导航栏上的反馈。")
|
||||
}
|
||||
|
||||
});
|
||||
return false;
|
||||
}
|
||||
});
|
||||
function refresh_captcha(){
|
||||
$("#captcha-img")[0].src = "/captcha/?" + Math.random();
|
||||
$("#captcha")[0].value = "";
|
||||
}
|
||||
$("#captcha-img").click(function(){
|
||||
refresh_captcha();
|
||||
});
|
||||
});
|
||||
41
static/src/js/app/oj/account/resetPassword.js
Normal file
41
static/src/js/app/oj/account/resetPassword.js
Normal file
@@ -0,0 +1,41 @@
|
||||
require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, csrfTokenHeader) {
|
||||
var applied_captcha = false;
|
||||
$('form').validator().on('submit', function (e) {
|
||||
if (!e.isDefaultPrevented()) {
|
||||
var index = location.href.indexOf("/t/");
|
||||
var token = location.href.substr(36+3, 32);
|
||||
var captcha = $("#captcha").val();
|
||||
var password = $("#new_password").val();
|
||||
$.ajax({
|
||||
beforeSend: csrfTokenHeader,
|
||||
url: "/api/reset_password/",
|
||||
data: {password: password, captcha: captcha, token:token},
|
||||
dataType: "json",
|
||||
method: "post",
|
||||
success: function (data) {
|
||||
if (!data.code) {
|
||||
refresh_captcha();
|
||||
bsAlert(data.data);
|
||||
window.location.href = "/login/";
|
||||
}
|
||||
else {
|
||||
refresh_captcha();
|
||||
bsAlert(data.data);
|
||||
}
|
||||
},
|
||||
error: function(){
|
||||
bsAlert("额 好像出错了,请刷新页面重试。如还有问题,请填写页面导航栏上的反馈。")
|
||||
}
|
||||
|
||||
});
|
||||
return false;
|
||||
}
|
||||
});
|
||||
function refresh_captcha(){
|
||||
$("#captcha-img")[0].src = "/captcha/?" + Math.random();
|
||||
$("#captcha")[0].value = "";
|
||||
}
|
||||
$("#captcha-img").click(function(){
|
||||
refresh_captcha();
|
||||
});
|
||||
});
|
||||
@@ -57,25 +57,28 @@
|
||||
problem_2_pack: "app/oj/problem/problem",
|
||||
submissionList_3_pack: "app/admin/problem/submissionList",
|
||||
contestCountdown_4_pack: "app/oj/contest/contestCountdown",
|
||||
addProblem_5_pack: "app/admin/problem/addProblem",
|
||||
problem_6_pack: "app/admin/problem/problem",
|
||||
contestList_7_pack: "app/admin/contest/contestList",
|
||||
admin_8_pack: "app/admin/admin",
|
||||
login_9_pack: "app/oj/account/login",
|
||||
addContest_10_pack: "app/admin/contest/addContest",
|
||||
contestPassword_11_pack: "app/oj/contest/contestPassword",
|
||||
changePassword_12_pack: "app/oj/account/changePassword",
|
||||
monitor_13_pack: "app/admin/monitor/monitor",
|
||||
editProblem_14_pack: "app/admin/contest/editProblem",
|
||||
joinGroupRequestList_15_pack: "app/admin/group/joinGroupRequestList",
|
||||
group_16_pack: "app/oj/group/group",
|
||||
contestProblemList_17_pack: "app/admin/contest/contestProblemList",
|
||||
editProblem_18_pack: "app/admin/problem/editProblem",
|
||||
register_19_pack: "app/oj/account/register",
|
||||
groupDetail_20_pack: "app/admin/group/groupDetail",
|
||||
editContest_21_pack: "app/admin/contest/editContest",
|
||||
group_22_pack: "app/admin/group/group",
|
||||
settings_23_pack: "app/oj/account/settings"
|
||||
avatar_5_pack: "app/oj/account/avatar",
|
||||
addProblem_6_pack: "app/admin/problem/addProblem",
|
||||
problem_7_pack: "app/admin/problem/problem",
|
||||
contestList_8_pack: "app/admin/contest/contestList",
|
||||
admin_9_pack: "app/admin/admin",
|
||||
login_10_pack: "app/oj/account/login",
|
||||
applyResetPassword_11_pack: "app/oj/account/applyResetPassword",
|
||||
addContest_12_pack: "app/admin/contest/addContest",
|
||||
contestPassword_13_pack: "app/oj/contest/contestPassword",
|
||||
changePassword_14_pack: "app/oj/account/changePassword",
|
||||
monitor_15_pack: "app/admin/monitor/monitor",
|
||||
editProblem_16_pack: "app/admin/contest/editProblem",
|
||||
joinGroupRequestList_17_pack: "app/admin/group/joinGroupRequestList",
|
||||
group_18_pack: "app/oj/group/group",
|
||||
contestProblemList_19_pack: "app/admin/contest/contestProblemList",
|
||||
editProblem_20_pack: "app/admin/problem/editProblem",
|
||||
register_21_pack: "app/oj/account/register",
|
||||
groupDetail_22_pack: "app/admin/group/groupDetail",
|
||||
editContest_23_pack: "app/admin/contest/editContest",
|
||||
resetPassword_24_pack: "app/oj/account/resetPassword",
|
||||
group_25_pack: "app/admin/group/group",
|
||||
settings_26_pack: "app/oj/account/settings"
|
||||
},
|
||||
shim: {
|
||||
avalon: {
|
||||
@@ -86,12 +89,6 @@
|
||||
appDir: "../",
|
||||
dir: "../../release/",
|
||||
modules: [
|
||||
{
|
||||
name: "bootstrap",
|
||||
},
|
||||
{
|
||||
name: "codeMirror"
|
||||
},
|
||||
{
|
||||
name: "announcement_0_pack"
|
||||
},
|
||||
@@ -108,62 +105,71 @@
|
||||
name: "contestCountdown_4_pack"
|
||||
},
|
||||
{
|
||||
name: "addProblem_5_pack"
|
||||
name: "avatar_5_pack"
|
||||
},
|
||||
{
|
||||
name: "problem_6_pack"
|
||||
name: "addProblem_6_pack"
|
||||
},
|
||||
{
|
||||
name: "contestList_7_pack"
|
||||
name: "problem_7_pack"
|
||||
},
|
||||
{
|
||||
name: "admin_8_pack"
|
||||
name: "contestList_8_pack"
|
||||
},
|
||||
{
|
||||
name: "login_9_pack"
|
||||
name: "admin_9_pack"
|
||||
},
|
||||
{
|
||||
name: "addContest_10_pack"
|
||||
name: "login_10_pack"
|
||||
},
|
||||
{
|
||||
name: "contestPassword_11_pack"
|
||||
name: "applyResetPassword_11_pack"
|
||||
},
|
||||
{
|
||||
name: "changePassword_12_pack"
|
||||
name: "addContest_12_pack"
|
||||
},
|
||||
{
|
||||
name: "monitor_13_pack"
|
||||
name: "contestPassword_13_pack"
|
||||
},
|
||||
{
|
||||
name: "editProblem_14_pack"
|
||||
name: "changePassword_14_pack"
|
||||
},
|
||||
{
|
||||
name: "joinGroupRequestList_15_pack"
|
||||
name: "monitor_15_pack"
|
||||
},
|
||||
{
|
||||
name: "group_16_pack"
|
||||
name: "editProblem_16_pack"
|
||||
},
|
||||
{
|
||||
name: "contestProblemList_17_pack"
|
||||
name: "joinGroupRequestList_17_pack"
|
||||
},
|
||||
{
|
||||
name: "editProblem_18_pack"
|
||||
name: "group_18_pack"
|
||||
},
|
||||
{
|
||||
name: "register_19_pack"
|
||||
name: "contestProblemList_19_pack"
|
||||
},
|
||||
{
|
||||
name: "groupDetail_20_pack"
|
||||
name: "editProblem_20_pack"
|
||||
},
|
||||
{
|
||||
name: "editContest_21_pack"
|
||||
name: "register_21_pack"
|
||||
},
|
||||
{
|
||||
name: "group_22_pack"
|
||||
name: "groupDetail_22_pack"
|
||||
},
|
||||
{
|
||||
name: "settings_23_pack"
|
||||
name: "editContest_23_pack"
|
||||
},
|
||||
{
|
||||
name: "resetPassword_24_pack"
|
||||
},
|
||||
{
|
||||
name: "group_25_pack"
|
||||
},
|
||||
{
|
||||
name: "settings_26_pack"
|
||||
}
|
||||
],
|
||||
optimizeCss: "standard",
|
||||
})
|
||||
@@ -59,25 +59,28 @@ var require = {
|
||||
problem_2_pack: "app/oj/problem/problem",
|
||||
submissionList_3_pack: "app/admin/problem/submissionList",
|
||||
contestCountdown_4_pack: "app/oj/contest/contestCountdown",
|
||||
addProblem_5_pack: "app/admin/problem/addProblem",
|
||||
problem_6_pack: "app/admin/problem/problem",
|
||||
contestList_7_pack: "app/admin/contest/contestList",
|
||||
admin_8_pack: "app/admin/admin",
|
||||
login_9_pack: "app/oj/account/login",
|
||||
addContest_10_pack: "app/admin/contest/addContest",
|
||||
contestPassword_11_pack: "app/oj/contest/contestPassword",
|
||||
changePassword_12_pack: "app/oj/account/changePassword",
|
||||
monitor_13_pack: "app/admin/monitor/monitor",
|
||||
editProblem_14_pack: "app/admin/contest/editProblem",
|
||||
joinGroupRequestList_15_pack: "app/admin/group/joinGroupRequestList",
|
||||
group_16_pack: "app/oj/group/group",
|
||||
contestProblemList_17_pack: "app/admin/contest/contestProblemList",
|
||||
editProblem_18_pack: "app/admin/problem/editProblem",
|
||||
register_19_pack: "app/oj/account/register",
|
||||
groupDetail_20_pack: "app/admin/group/groupDetail",
|
||||
editContest_21_pack: "app/admin/contest/editContest",
|
||||
group_22_pack: "app/admin/group/group",
|
||||
settings_23_pack: "app/oj/account/settings"
|
||||
avatar_5_pack: "app/oj/account/avatar",
|
||||
addProblem_6_pack: "app/admin/problem/addProblem",
|
||||
problem_7_pack: "app/admin/problem/problem",
|
||||
contestList_8_pack: "app/admin/contest/contestList",
|
||||
admin_9_pack: "app/admin/admin",
|
||||
login_10_pack: "app/oj/account/login",
|
||||
applyResetPassword_11_pack: "app/oj/account/applyResetPassword",
|
||||
addContest_12_pack: "app/admin/contest/addContest",
|
||||
contestPassword_13_pack: "app/oj/contest/contestPassword",
|
||||
changePassword_14_pack: "app/oj/account/changePassword",
|
||||
monitor_15_pack: "app/admin/monitor/monitor",
|
||||
editProblem_16_pack: "app/admin/contest/editProblem",
|
||||
joinGroupRequestList_17_pack: "app/admin/group/joinGroupRequestList",
|
||||
group_18_pack: "app/oj/group/group",
|
||||
contestProblemList_19_pack: "app/admin/contest/contestProblemList",
|
||||
editProblem_20_pack: "app/admin/problem/editProblem",
|
||||
register_21_pack: "app/oj/account/register",
|
||||
groupDetail_22_pack: "app/admin/group/groupDetail",
|
||||
editContest_23_pack: "app/admin/contest/editContest",
|
||||
resetPassword_24_pack: "app/oj/account/resetPassword",
|
||||
group_25_pack: "app/admin/group/group",
|
||||
settings_26_pack: "app/oj/account/settings",
|
||||
},
|
||||
shim: {
|
||||
avalon: {
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
<div ms-controller="add_contest">
|
||||
<form id="add-contest-form">
|
||||
<div class="col-md-9">
|
||||
<div class="alert alert-warning" role="alert">
|
||||
<p>注意!管理员在测试比赛题目的时候请务必保持比赛状态为没有开始,这时只有管理员可以正常查看和提交题目,而且不会产生排名。</p>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<label>比赛名称</label>
|
||||
</div>
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
aria-hidden="true">←</span> 返回</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
<div class="alert alert-warning" role="alert">
|
||||
<p>注意!管理员在测试比赛题目的时候请务必保持比赛状态为没有开始,这时只有管理员可以正常查看和提交题目,而且不会产生排名。</p>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<label>比赛名称</label>
|
||||
</div>
|
||||
|
||||
40
template/src/oj/account/apply_reset_password.html
Normal file
40
template/src/oj/account/apply_reset_password.html
Normal file
@@ -0,0 +1,40 @@
|
||||
{% extends "oj_base.html" %}
|
||||
{% block title %}
|
||||
找回登录信息
|
||||
{% endblock %}
|
||||
{% block body %}
|
||||
<div class="container main">
|
||||
<div class="col-md-6 col-md-offset-3">
|
||||
<h2 class="text-center">找回登录信息</h2><br>
|
||||
<div>
|
||||
<p>请输入你注册时使用的邮箱地址,系统将自动向你的邮箱发送一封含有您登录信息的电子邮件,
|
||||
你可以看到你的用户名,并可以选择重新设置登录密码,注意为了你的账户安全,重置密码链接仅在30分钟内有效</p>
|
||||
</div>
|
||||
<br>
|
||||
<form id="login-form">
|
||||
<div class="form-group">
|
||||
<label for="email">注册电子邮件地址</label>
|
||||
<input type="email" class="form-control input-lg" id="email" name="email" placeholder="邮箱地址"
|
||||
data-remote="/api/email_check/?reset=true" data-remote-error="该邮箱未被注册!" data-error="请填写正确的邮箱地址"
|
||||
required>
|
||||
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
<div class="form-group" id="captcha-area">
|
||||
<label for="captcha">验证码</label> <img src="/captcha/" id="captcha-img">
|
||||
<small><p></p></small>
|
||||
<input type="text" class="form-control input-lg" id="captcha" name="captcha"
|
||||
placeholder="验证码" maxlength="4" data-error="请填写验证码" required>
|
||||
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary">提交</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block js_block %}
|
||||
<script src="/static/js/app/oj/account/applyResetPassword.js"></script>
|
||||
{% endblock %}
|
||||
@@ -36,7 +36,7 @@
|
||||
<div class="form-group">
|
||||
<label for="confirm_password">确认密码</label>
|
||||
<input type="password" class="form-control input-lg" id="confirm_password" name="confirm_password"
|
||||
placeholder="确认密码" maxlength="30" data-match="#new_password" data-match-error="两个密码不一致" required>
|
||||
placeholder="确认密码" maxlength="30" data-match="#new_password" data-match-error="两次密码不一致" required>
|
||||
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary">提交</button>
|
||||
</div>
|
||||
<a href="/reset_password/">忘记用户名/密码</a><br>
|
||||
<a href="/register/">还没有帐号?点击注册</a>
|
||||
|
||||
</form>
|
||||
|
||||
@@ -1,10 +1,53 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head lang="en">
|
||||
<meta charset="UTF-8">
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
{% extends "oj_base.html" %}
|
||||
{% block title %}
|
||||
找回登录信息
|
||||
{% endblock %}
|
||||
{% block body %}
|
||||
<div class="container main">
|
||||
<div class="col-md-6 col-md-offset-3">
|
||||
<h2 class="text-center">找回登录信息</h2><br>
|
||||
<br>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
<form id="login-form">
|
||||
<div class="form-group">
|
||||
<label for="email">注册电子邮件地址</label>
|
||||
<input type="text" class="form-control input-lg" name="email" value="{{ user.email }}" readonly>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="username">用户名</label>
|
||||
<input type="text" class="form-control input-lg" name="username" value="{{ user.username }}" readonly>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="new_password">新密码</label>
|
||||
<input type="password" class="form-control input-lg" id="new_password" name="new_password"
|
||||
placeholder="新密码" maxlength="30" data-minlength="6" data-error="密码不得少于6位" required>
|
||||
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="confirm_password">确认密码</label>
|
||||
<input type="password" class="form-control input-lg" id="confirm_password" name="confirm_password"
|
||||
placeholder="确认密码" maxlength="30" data-match="#new_password" data-error="请输入确认密码"
|
||||
data-match-error="两次密码不一致"
|
||||
required>
|
||||
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
<div class="form-group" id="captcha-area">
|
||||
<label for="captcha">验证码</label> <img src="/captcha/" id="captcha-img">
|
||||
<small><p></p></small>
|
||||
<input type="text" class="form-control input-lg" id="captcha" name="captcha"
|
||||
placeholder="验证码" maxlength="4" data-error="请填写验证码" required>
|
||||
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary">提交</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block js_block %}
|
||||
<script src="/static/js/app/oj/account/resetPassword.js"></script>
|
||||
{% endblock %}
|
||||
@@ -100,6 +100,15 @@
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
.section{
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
#section0{
|
||||
background-image: url(/static/img/index/bg/bg3.jpg);
|
||||
padding: 0 0 0 0;
|
||||
}
|
||||
|
||||
</style>
|
||||
<link rel="stylesheet" href="/static/css/animate/animate.css">
|
||||
|
||||
@@ -110,12 +119,21 @@
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function () {
|
||||
$('#fullpage').fullpage({
|
||||
sectionsColor: ['#28ac72', '#2f7ddb', '#FAC832', '#B01414'],
|
||||
sectionsColor: ['#ffffff', '#2f7ddb', '#FAC832', '#B01414'],
|
||||
css3: true,
|
||||
navigation: true,
|
||||
loopBottom: true
|
||||
});
|
||||
});
|
||||
|
||||
/*
|
||||
var c = 0;
|
||||
|
||||
setInterval(function(){
|
||||
//alert(1);
|
||||
$("#section0").css("background-image", "url(/static/img/index/bg/bg" + (c++ % 4).toString() + ".jpg)")
|
||||
}, 1000)
|
||||
*/
|
||||
</script>
|
||||
|
||||
</head>
|
||||
@@ -172,7 +190,7 @@
|
||||
<div class="section-text">
|
||||
<img class="icon" id="img3" src="/static/img/index/m.png">
|
||||
|
||||
<h1>自由举办小组赛(10月上线)</h1>
|
||||
<h1>自由举办小组赛(12月上线)</h1>
|
||||
|
||||
<h3>内部比赛,日常作业,期末考试,通通搞定</h3>
|
||||
</div>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<tbody>
|
||||
<tr height="39" style="background-color:#50a5e6;">
|
||||
<td style="padding-left:15px;font-family:'微软雅黑','黑体',arial;">
|
||||
{{ website_name }} 密码找回邮件
|
||||
{{ website_name }} 登录信息找回
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -32,12 +32,12 @@
|
||||
</tr>
|
||||
<tr height="30">
|
||||
<td style="padding-left:55px;padding-right:55px;font-family:'微软雅黑','黑体',arial;font-size:14px;">
|
||||
您刚刚在 {{ website_name }} 使用了找回密码功能。
|
||||
您刚刚在 {{ 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)">60分钟</span>内点击下面链接设置您的新密码:
|
||||
请在<span style="color:rgb(255,0,0)">30分钟</span>内点击下面链接设置您的新密码:
|
||||
</td>
|
||||
</tr>
|
||||
<tr height="60">
|
||||
@@ -63,7 +63,8 @@
|
||||
</tr>
|
||||
<tr height="20">
|
||||
<td style="padding-left:55px;padding-right:55px;font-family:'微软雅黑','黑体',arial;font-size:12px;">
|
||||
如果你没有提出过密码修改申请,请忽略此邮件。有可能是其他用户误填了你的用户名。我们不会对你的帐户进行任何修改。
|
||||
如果您没有提出过该申请,请忽略此邮件。有可能是其他用户误填了您的邮件地址,我们不会对你的帐户进行任何修改。
|
||||
请不要向他人透露本邮件的内容,否则可能会导致您的账号被盗。
|
||||
</td>
|
||||
</tr>
|
||||
<tr height="20">
|
||||
|
||||
15
utils/mail.py
Normal file
15
utils/mail.py
Normal file
@@ -0,0 +1,15 @@
|
||||
# coding=utf-8
|
||||
from envelopes import Envelope
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
def send_email(from_name, to_email, to_name, subject, content):
|
||||
envelope = Envelope(from_addr=(settings.SMTP_CONFIG["email"], from_name),
|
||||
to_addr=(to_email, to_name),
|
||||
subject=subject,
|
||||
html_body=content)
|
||||
envelope.send(settings.SMTP_CONFIG["smtp_server"],
|
||||
login=settings.SMTP_CONFIG["email"],
|
||||
password=settings.SMTP_CONFIG["password"],
|
||||
tls=settings.SMTP_CONFIG["tls"])
|
||||
Reference in New Issue
Block a user