diff --git a/account/serializers.py b/account/serializers.py index 6db6291..0aac07a 100644 --- a/account/serializers.py +++ b/account/serializers.py @@ -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) diff --git a/account/views.py b/account/views.py index 5edcd1e..2ba5739 100644 --- a/account/views.py +++ b/account/views.py @@ -148,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): @@ -273,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: @@ -285,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) @@ -353,4 +363,14 @@ class SSOAPIView(APIView): token = rand_str() request.user.auth_token = token request.user.save() - return render(request, "oj/account/sso.html", {"redirect_url": callback + "?token=" + token, "callback": callback}) \ No newline at end of file + 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}) diff --git a/contest/views.py b/contest/views.py index 7deb166..87378db 100644 --- a/contest/views.py +++ b/contest/views.py @@ -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")) diff --git a/oj/urls.py b/oj/urls.py index 6ba6b06..d2beba1 100644 --- a/oj/urls.py +++ b/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.+)/$', "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\w+)/$', "account.views.reset_password_page", name="reset_password_page") ] diff --git a/static/src/js/app/oj/account/applyResetPassword.js b/static/src/js/app/oj/account/applyResetPassword.js new file mode 100644 index 0000000..e8d31ed --- /dev/null +++ b/static/src/js/app/oj/account/applyResetPassword.js @@ -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(); + }); +}); \ No newline at end of file diff --git a/static/src/js/app/oj/account/resetPassword.js b/static/src/js/app/oj/account/resetPassword.js new file mode 100644 index 0000000..0f0bb4b --- /dev/null +++ b/static/src/js/app/oj/account/resetPassword.js @@ -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(); + }); +}); \ No newline at end of file diff --git a/template/src/admin/contest/add_contest.html b/template/src/admin/contest/add_contest.html index ce8fd14..010b73e 100644 --- a/template/src/admin/contest/add_contest.html +++ b/template/src/admin/contest/add_contest.html @@ -1,6 +1,9 @@
+
diff --git a/template/src/admin/contest/edit_contest.html b/template/src/admin/contest/edit_contest.html index 2afc849..08f7c09 100644 --- a/template/src/admin/contest/edit_contest.html +++ b/template/src/admin/contest/edit_contest.html @@ -6,6 +6,9 @@ aria-hidden="true">← 返回 +
diff --git a/template/src/oj/account/apply_reset_password.html b/template/src/oj/account/apply_reset_password.html new file mode 100644 index 0000000..5d65ccc --- /dev/null +++ b/template/src/oj/account/apply_reset_password.html @@ -0,0 +1,40 @@ +{% extends "oj_base.html" %} +{% block title %} + 找回登录信息 +{% endblock %} +{% block body %} +
+
+

找回登录信息


+
+

请输入你注册时使用的邮箱地址,系统将自动向你的邮箱发送一封含有您登录信息的电子邮件, + 你可以看到你的用户名,并可以选择重新设置登录密码,注意为了你的账户安全,重置密码链接仅在30分钟内有效

+
+
+ +
+ + + +
+
+
+    +

+ + +
+
+
+ +
+ +
+
+{% endblock %} +{% block js_block %} + +{% endblock %} \ No newline at end of file diff --git a/template/src/oj/account/change_password.html b/template/src/oj/account/change_password.html index 3f346e2..9fd1334 100644 --- a/template/src/oj/account/change_password.html +++ b/template/src/oj/account/change_password.html @@ -36,7 +36,7 @@
+ placeholder="确认密码" maxlength="30" data-match="#new_password" data-match-error="两次密码不一致" required>
diff --git a/template/src/oj/account/login.html b/template/src/oj/account/login.html index adc5ca9..eadb5cc 100644 --- a/template/src/oj/account/login.html +++ b/template/src/oj/account/login.html @@ -32,6 +32,7 @@
+ 忘记用户名/密码
还没有帐号?点击注册 diff --git a/template/src/oj/account/reset_password.html b/template/src/oj/account/reset_password.html index 71ce692..703ff6f 100644 --- a/template/src/oj/account/reset_password.html +++ b/template/src/oj/account/reset_password.html @@ -1,10 +1,53 @@ - - - - - - - +{% extends "oj_base.html" %} +{% block title %} + 找回登录信息 +{% endblock %} +{% block body %} +
+
+

找回登录信息


+
- - \ No newline at end of file +
+
+ + +
+
+ + +
+
+ + + +
+
+
+ + + +
+
+
+    +

+ + +
+
+
+ +
+
+
+
+{% endblock %} +{% block js_block %} + +{% endblock %} \ No newline at end of file diff --git a/template/src/utils/reset_password_email.html b/template/src/utils/reset_password_email.html index f4c8b93..5a0b591 100644 --- a/template/src/utils/reset_password_email.html +++ b/template/src/utils/reset_password_email.html @@ -8,7 +8,7 @@ - {{ website_name }} 密码找回邮件 + {{ website_name }} 登录信息找回 @@ -32,12 +32,12 @@ - 您刚刚在 {{ website_name }} 使用了找回密码功能。 + 您刚刚在 {{ website_name }} 申请了找回登录信息服务。 - 请在60分钟内点击下面链接设置您的新密码: + 请在30分钟内点击下面链接设置您的新密码: @@ -63,7 +63,8 @@ - 如果你没有提出过密码修改申请,请忽略此邮件。有可能是其他用户误填了你的用户名。我们不会对你的帐户进行任何修改。 + 如果您没有提出过该申请,请忽略此邮件。有可能是其他用户误填了您的邮件地址,我们不会对你的帐户进行任何修改。 + 请不要向他人透露本邮件的内容,否则可能会导致您的账号被盗。