From 90eaadbb1c1efad809879d404d2df7ff50d45153 Mon Sep 17 00:00:00 2001 From: sxw Date: Mon, 3 Aug 2015 16:34:55 +0800 Subject: [PATCH 01/11] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=86=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E6=B3=A8=E5=86=8C=E9=A1=B5=E9=9D=A2=E5=92=8C=E5=AF=B9?= =?UTF-8?q?=E5=BA=94=E7=9A=84urls=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- oj/urls.py | 1 + template/oj/account/register.html | 42 ++++++++++++++++++++++++------- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/oj/urls.py b/oj/urls.py index 260a42a..84b1363 100644 --- a/oj/urls.py +++ b/oj/urls.py @@ -10,6 +10,7 @@ urlpatterns = [ url(r'^docs/', include('rest_framework_swagger.urls')), url(r'^admin/$', TemplateView.as_view(template_name="admin/index.html"), name="admin_index_page"), url(r'^login/$', TemplateView.as_view(template_name="oj/account/login.html"), name="user_login_page"), + url(r'^register/$', TemplateView.as_view(template_name="oj/account/register.html"), name="user_register_page"), url(r'^api/login/$', UserLoginAPIView.as_view(), name="login_api"), url(r'^api/login/$', UserLoginAPIView.as_view(), name="user_login_api"), url(r'^problem/(?P\d+)/$', "problem.views.problem_page", name="problem_page"), diff --git a/template/oj/account/register.html b/template/oj/account/register.html index 71ce692..a93014c 100644 --- a/template/oj/account/register.html +++ b/template/oj/account/register.html @@ -1,10 +1,34 @@ - - - - - - - +{% extends "oj_base.html" %} +{% block body %} +
+
+

用户注册

- - \ No newline at end of file +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+
+
+{% endblock %} +{% block js_block %} + +{% endblock %} \ No newline at end of file From 2454db54b0e725dcfd1b1e502c82da66b0727876 Mon Sep 17 00:00:00 2001 From: sxw Date: Mon, 3 Aug 2015 16:37:20 +0800 Subject: [PATCH 02/11] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BA=86=E7=A9=BA?= =?UTF-8?q?=E6=A0=BC=E5=92=8Ctab=E6=B7=B7=E5=90=88=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- oj/urls.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oj/urls.py b/oj/urls.py index 84b1363..b308320 100644 --- a/oj/urls.py +++ b/oj/urls.py @@ -10,7 +10,7 @@ urlpatterns = [ url(r'^docs/', include('rest_framework_swagger.urls')), url(r'^admin/$', TemplateView.as_view(template_name="admin/index.html"), name="admin_index_page"), url(r'^login/$', TemplateView.as_view(template_name="oj/account/login.html"), name="user_login_page"), - url(r'^register/$', TemplateView.as_view(template_name="oj/account/register.html"), name="user_register_page"), + url(r'^register/$', TemplateView.as_view(template_name="oj/account/register.html"), name="user_register_page"), url(r'^api/login/$', UserLoginAPIView.as_view(), name="login_api"), url(r'^api/login/$', UserLoginAPIView.as_view(), name="user_login_api"), url(r'^problem/(?P\d+)/$', "problem.views.problem_page", name="problem_page"), From 3ccb7740f2f671efecc711f35a9d11735d7d6f5d Mon Sep 17 00:00:00 2001 From: sxw Date: Tue, 4 Aug 2015 14:55:38 +0800 Subject: [PATCH 03/11] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=86=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E5=AF=86=E7=A0=81=E7=9A=84=E9=A1=B5=E9=9D=A2=E5=92=8C?= =?UTF-8?q?js?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- oj/urls.py | 1 + .../src/js/app/oj/account/change_password.js | 89 +++++++++++++++++++ static/src/js/config.js | 1 + .../lib/formValidation/validator/confirm.js | 34 +++++++ template/oj/account/change_password.html | 42 +++++++-- 5 files changed, 158 insertions(+), 9 deletions(-) create mode 100644 static/src/js/app/oj/account/change_password.js create mode 100644 static/src/js/lib/formValidation/validator/confirm.js diff --git a/oj/urls.py b/oj/urls.py index b308320..f9d4cbf 100644 --- a/oj/urls.py +++ b/oj/urls.py @@ -11,6 +11,7 @@ urlpatterns = [ url(r'^admin/$', TemplateView.as_view(template_name="admin/index.html"), name="admin_index_page"), url(r'^login/$', TemplateView.as_view(template_name="oj/account/login.html"), name="user_login_page"), url(r'^register/$', TemplateView.as_view(template_name="oj/account/register.html"), name="user_register_page"), + url(r'^change_password/$', TemplateView.as_view(template_name="oj/account/change_password.html"), name="user_change_password_page"), url(r'^api/login/$', UserLoginAPIView.as_view(), name="login_api"), url(r'^api/login/$', UserLoginAPIView.as_view(), name="user_login_api"), url(r'^problem/(?P\d+)/$', "problem.views.problem_page", name="problem_page"), diff --git a/static/src/js/app/oj/account/change_password.js b/static/src/js/app/oj/account/change_password.js new file mode 100644 index 0000000..035e0d3 --- /dev/null +++ b/static/src/js/app/oj/account/change_password.js @@ -0,0 +1,89 @@ + +require(["jquery", "bs_alert", "validation"], function($, bs_alert){ + + + $("#change_password-form").formValidation({ + framework: "bootstrap", + fields: { + username: { + validators: { + notEmpty: { + message: "请填写用户名" + } + } + }, + password: { + validators: { + notEmpty: { + message: "请填写旧密码" + } + } + }, + new_password: { + validators: { + notEmpty: { + message: "请填写新密码" + }, + stringLength: { + min: 6, + max: 30, + message: '密码长度必须在6到30位之间' + }, + confirm: { + firstPassword: $("#new_password"), + secondPassword: $("#confirm_password"), + message: "两次输入的密码必须一致" + } + }, + onSuccess: function(e, data) { + + if (!data.fv.isValidField('confirm_password')) { + data.fv.revalidateField('confirm_password'); + } + } + + }, + confirm_password: { + validators: { + notEmpty: { + message: "请填写确认密码" + }, + confirm: { + firstPassword: $("#new_password"), + secondPassword: $("#confirm_password"), + message: "两次输入的密码必须一致" + } + }, + onSuccess: function(e, data) { + + if (!data.fv.isValidField('new_password')) { + data.fv.revalidateField('new_password'); + } + } + } + } + } + ).on('success.form.fv', function(e) { + e.preventDefault(); + var username = $("#username").val(); + var new_password = $("#new_password ").val(); + var password = $("#password").val(); + $.ajax({ + url: "/api/change_password/", + data: {username: username, new_password: new_password , old_password : password}, + dataType: "json", + method: "post", + success: function (data) { + + if(!data.code){ + window.location.href="/login/"; + } + else{ + bs_alert(data.data); + } + } + + }) + }); + +}); \ No newline at end of file diff --git a/static/src/js/config.js b/static/src/js/config.js index dc17a5a..fbeaa3a 100644 --- a/static/src/js/config.js +++ b/static/src/js/config.js @@ -25,6 +25,7 @@ var require = { "validator/date": "lib/formValidation/validator/date", "validator/integer": "lib/formValidation/validator/integer", "validator/between": "lib/formValidation/validator/between", + 'validator/confirm':"lib/formValidation/validator/confirm", //富文本编辑器 不要直接使用,而是使用上面的editor simditor: "lib/simditor/simditor", diff --git a/static/src/js/lib/formValidation/validator/confirm.js b/static/src/js/lib/formValidation/validator/confirm.js new file mode 100644 index 0000000..5d491ee --- /dev/null +++ b/static/src/js/lib/formValidation/validator/confirm.js @@ -0,0 +1,34 @@ +/** + * confirm validator + */ + +(function(root, factory) { + + "use strict"; + + // AMD module is defined + if (typeof define === "function" && define.amd) { + define("validator/confirm", ["jquery", "base"], factory); + } else { + // planted over the root! + factory(root.jQuery, root.FormValidation); + } + +}(this, function ($, FormValidation) { + FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { + 'en_US': { + confirm: { + 'default': 'Please input the same value' + } + } + }); + + FormValidation.Validator.confirm = { + + validate: function(validator, $field, options) { + if (options.firstPassword.val() == options.secondPassword.val() ||options.secondPassword.val()== '') + return true; + return false; + } + }; +})); diff --git a/template/oj/account/change_password.html b/template/oj/account/change_password.html index 71ce692..65de447 100644 --- a/template/oj/account/change_password.html +++ b/template/oj/account/change_password.html @@ -1,10 +1,34 @@ - - - - - - - +{% extends "oj_base.html" %} +{% block body %} +
+
+

修改密码

- - \ No newline at end of file +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+
+
+{% endblock %} +{% block js_block %} + +{% endblock %} \ No newline at end of file From 58a664af1b0852b95517c11cf85d8a04bc1e6770 Mon Sep 17 00:00:00 2001 From: sxw Date: Tue, 4 Aug 2015 14:56:17 +0800 Subject: [PATCH 04/11] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=86=E6=B3=A8?= =?UTF-8?q?=E5=86=8Cjs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- static/src/js/app/oj/account/register.js | 94 ++++++++++++++++++++++++ static/src/js/utils/validation.js | 5 +- 2 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 static/src/js/app/oj/account/register.js diff --git a/static/src/js/app/oj/account/register.js b/static/src/js/app/oj/account/register.js new file mode 100644 index 0000000..0241698 --- /dev/null +++ b/static/src/js/app/oj/account/register.js @@ -0,0 +1,94 @@ +require(["jquery", "bs_alert", "validation"], function($, bs_alert){ + + $("#register-form") + .formValidation({ + framework: "bootstrap", + fields: { + username: { + validators: { + notEmpty: { + message: "请填写用户名" + }, + stringLength: { + min: 3, + max: 30, + message: '用户名长度必须在3到30位之间' + } + } + }, + password: { + validators: { + notEmpty: { + message: "请填写密码" + }, + stringLength: { + min: 6, + max: 30, + message: '密码长度必须在6到30位之间' + }, + confirm: { + firstPassword: $("#password"), + secondPassword: $("#confirm_password"), + message: "两次输入的密码必须一致" + } + }, + onSuccess: function(e, data) { + + if (!data.fv.isValidField('confirm_password')) { + data.fv.revalidateField('confirm_password'); + } + } + }, + real_name: { + validators: { + notEmpty: { + message: "请填写真实姓名" + } + }, + + }, + confirm_password: { + validators: { + notEmpty: { + message: "请填写确认密码" + }, + confirm: { + firstPassword: $("#password"), + secondPassword: $("#confirm_password"), + message: "两次输入的密码必须一致" + } + + }, + + onSuccess: function(e, data) { + + if (!data.fv.isValidField('password')) { + data.fv.revalidateField('password'); + } + } + } + } + } + ).on('success.form.fv', function(e) { + e.preventDefault(); + var username = $("#username").val(); + var real_name = $("#real_name").val(); + var password = $("#password").val(); + $.ajax({ + url: "/api/register/", + data: {username: username, real_name: real_name, password: password}, + dataType: "json", + method: "post", + success: function (data) { + if(!data.code){ + window.location.href="/login/"; + } + else{ + bs_alert(data.data); + } + } + + }) + }); + +}); \ No newline at end of file diff --git a/static/src/js/utils/validation.js b/static/src/js/utils/validation.js index ab3c2e7..b79bd81 100644 --- a/static/src/js/utils/validation.js +++ b/static/src/js/utils/validation.js @@ -7,5 +7,8 @@ define("validation", 'validator/stringLength', 'validator/date', 'validator/integer', - 'validator/between'], function () { + 'validator/between', + 'validator/confirm'], + function () { + }); \ No newline at end of file From 62a9e050f5ea05cc271edb31c37d505bc08f992e Mon Sep 17 00:00:00 2001 From: sxw Date: Tue, 4 Aug 2015 16:05:40 +0800 Subject: [PATCH 05/11] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BA=86=E7=99=BB?= =?UTF-8?q?=E9=99=86=EF=BC=8C=E4=BF=AE=E6=94=B9=E5=AF=86=E7=A0=81=EF=BC=8C?= =?UTF-8?q?=E6=B3=A8=E5=86=8C=E4=B8=89=E4=B8=AA=E9=A1=B5=E9=9D=A2=E7=9A=84?= =?UTF-8?q?csrf=EF=BC=9B=20=E6=B7=BB=E5=8A=A0=E4=BA=86usernameCheck?= =?UTF-8?q?=E7=9A=84valuedation=E6=A3=80=E6=B5=8B=E6=96=B9=E6=B3=95;=20url?= =?UTF-8?q?s.py=20=E6=B7=BB=E5=8A=A0=E4=BA=86register=EF=BC=8Cchange=5Fpas?= =?UTF-8?q?sword=E9=A1=B5=E9=9D=A2=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- oj/urls.py | 2 + .../src/js/app/oj/account/change_password.js | 3 +- static/src/js/app/oj/account/login.js | 3 +- static/src/js/app/oj/account/register.js | 6 ++- static/src/js/config.js | 3 +- .../formValidation/validator/usernameCheck.js | 44 +++++++++++++++++++ static/src/js/utils/csrf.js | 16 +++++++ static/src/js/utils/validation.js | 3 +- 8 files changed, 75 insertions(+), 5 deletions(-) create mode 100644 static/src/js/lib/formValidation/validator/usernameCheck.js create mode 100644 static/src/js/utils/csrf.js diff --git a/oj/urls.py b/oj/urls.py index fc652b3..aa35a62 100644 --- a/oj/urls.py +++ b/oj/urls.py @@ -10,6 +10,8 @@ urlpatterns = [ url(r'^docs/', include('rest_framework_swagger.urls')), url(r'^admin/$', TemplateView.as_view(template_name="admin/index.html"), name="admin_index_page"), url(r'^login/$', TemplateView.as_view(template_name="oj/account/login.html"), name="user_login_page"), + url(r'^register/$', TemplateView.as_view(template_name="oj/account/register.html"), name="user_register_page"), + url(r'^change_password/$', TemplateView.as_view(template_name="oj/account/change_password.html"), name="user_change_password_page"), url(r'^api/login/$', UserLoginAPIView.as_view(), name="user_login_api"), url(r'^api/register/$', UserRegisterAPIView.as_view(), name="user_register_api"), url(r'^api/change_password/$', UserChangePasswordAPIView.as_view(), name="user_change_password_api"), diff --git a/static/src/js/app/oj/account/change_password.js b/static/src/js/app/oj/account/change_password.js index 035e0d3..ff9bf74 100644 --- a/static/src/js/app/oj/account/change_password.js +++ b/static/src/js/app/oj/account/change_password.js @@ -1,5 +1,5 @@ -require(["jquery", "bs_alert", "validation"], function($, bs_alert){ +require(["jquery", "bs_alert", "csrf", "validation"], function($, bs_alert, csrfHeader){ $("#change_password-form").formValidation({ @@ -69,6 +69,7 @@ require(["jquery", "bs_alert", "validation"], function($, bs_alert){ var new_password = $("#new_password ").val(); var password = $("#password").val(); $.ajax({ + beforeSend: csrfHeader, url: "/api/change_password/", data: {username: username, new_password: new_password , old_password : password}, dataType: "json", diff --git a/static/src/js/app/oj/account/login.js b/static/src/js/app/oj/account/login.js index b7c23e7..da4416d 100644 --- a/static/src/js/app/oj/account/login.js +++ b/static/src/js/app/oj/account/login.js @@ -1,4 +1,4 @@ -require(["jquery", "bs_alert", "validation"], function($, bs_alert){ +require(["jquery", "bs_alert", "csrf", "validation"], function($, bs_alert, csrfHeader){ $("#login-form") .formValidation({ framework: "bootstrap", @@ -24,6 +24,7 @@ require(["jquery", "bs_alert", "validation"], function($, bs_alert){ var username = $("#username").val(); var password = $("#password").val(); $.ajax({ + beforeSend: csrfHeader, url: "/api/login/", data: {username: username, password: password}, dataType: "json", diff --git a/static/src/js/app/oj/account/register.js b/static/src/js/app/oj/account/register.js index 0241698..4baf334 100644 --- a/static/src/js/app/oj/account/register.js +++ b/static/src/js/app/oj/account/register.js @@ -1,4 +1,4 @@ -require(["jquery", "bs_alert", "validation"], function($, bs_alert){ +require(["jquery", "bs_alert", "csrf", "validation"], function($, bs_alert, csrfHeader){ $("#register-form") .formValidation({ @@ -13,6 +13,9 @@ require(["jquery", "bs_alert", "validation"], function($, bs_alert){ min: 3, max: 30, message: '用户名长度必须在3到30位之间' + }, + usernameCheck:{ + message: '用户名已存在' } } }, @@ -75,6 +78,7 @@ require(["jquery", "bs_alert", "validation"], function($, bs_alert){ var real_name = $("#real_name").val(); var password = $("#password").val(); $.ajax({ + beforeSend: csrfHeader, url: "/api/register/", data: {username: username, real_name: real_name, password: password}, dataType: "json", diff --git a/static/src/js/config.js b/static/src/js/config.js index fbeaa3a..3907d1c 100644 --- a/static/src/js/config.js +++ b/static/src/js/config.js @@ -14,6 +14,7 @@ var require = { bs_alert: "utils/bs_alert", submit_code: "app/oj/problem/submit_code", contest: "app/admin/contest/contest", + csrf: "utils/csrf", //formValidation 不要在代码中单独使用,而是使用和修改utils/validation base: "lib/formValidation/base", @@ -26,7 +27,7 @@ var require = { "validator/integer": "lib/formValidation/validator/integer", "validator/between": "lib/formValidation/validator/between", 'validator/confirm':"lib/formValidation/validator/confirm", - + "validator/usernameCheck":"lib/formValidation/validator/usernameCheck", //富文本编辑器 不要直接使用,而是使用上面的editor simditor: "lib/simditor/simditor", "simple-module": "lib/simditor/module", diff --git a/static/src/js/lib/formValidation/validator/usernameCheck.js b/static/src/js/lib/formValidation/validator/usernameCheck.js new file mode 100644 index 0000000..116c1dc --- /dev/null +++ b/static/src/js/lib/formValidation/validator/usernameCheck.js @@ -0,0 +1,44 @@ +/** + * usernameCheck validator + */ + +(function(root, factory) { + + "use strict"; + + // AMD module is defined + if (typeof define === "function" && define.amd) { + define("validator/usernameCheck", ["jquery", "base", "csrf"], factory); + } else { + // planted over the root! + factory(root.jQuery, root.FormValidation); + } + +}(this, function ($, FormValidation, csrfHeader) { + FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { + 'en_US': { + usernameCheck: { + 'default': 'Please input the same value' + } + } + }); + + FormValidation.Validator.usernameCheck = { + + validate: function(validator, $field, options) { + if ($field.val() == '') + return true; + return !$.ajax({ + async: false, + beforeSend: csrfHeader, + url: "/api/username_check/", + data: {username: $field.val()}, + dataType: "json", + method: "post", + + + }).responseJSON.data; + + } + }; +})); diff --git a/static/src/js/utils/csrf.js b/static/src/js/utils/csrf.js new file mode 100644 index 0000000..767542b --- /dev/null +++ b/static/src/js/utils/csrf.js @@ -0,0 +1,16 @@ +define("csrf",function(){ + function get_cookie(cookie_name) { + var name = cookie_name + "="; + var ca = document.cookie.split(';'); + for (var i = 0; i < ca.length; i++) { + var c = ca[i]; + while (c.charAt(0) == ' ') c = c.substring(1); + if (c.indexOf(name) != -1) return c.substring(name.length, c.length); + } + return ""; + } + function csrfHeader(xhr){ + xhr.setRequestHeader("X-CSRFToken", get_cookie("csrftoken")); + } + return csrfHeader; +}); diff --git a/static/src/js/utils/validation.js b/static/src/js/utils/validation.js index b79bd81..38788f7 100644 --- a/static/src/js/utils/validation.js +++ b/static/src/js/utils/validation.js @@ -8,7 +8,8 @@ define("validation", 'validator/date', 'validator/integer', 'validator/between', - 'validator/confirm'], + 'validator/confirm', + 'validator/usernameCheck'], function () { }); \ No newline at end of file From 76aba7f0e7f7b012425f6efcc5bae06daca1f40a Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Tue, 4 Aug 2015 18:38:00 +0800 Subject: [PATCH 06/11] add coverage requirement and run test shell script --- requirements.txt | 3 ++- tools/runserver.sh | 2 ++ tools/runtest.sh | 4 ++++ 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 tools/runserver.sh create mode 100644 tools/runtest.sh diff --git a/requirements.txt b/requirements.txt index 00da332..bb0fce3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,4 +5,5 @@ django-redis-sessions djangorestframework django-rest-swagger celery -gunicorn \ No newline at end of file +gunicorn +coverage \ No newline at end of file diff --git a/tools/runserver.sh b/tools/runserver.sh new file mode 100644 index 0000000..d508cfc --- /dev/null +++ b/tools/runserver.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +python manage.py runserver \ No newline at end of file diff --git a/tools/runtest.sh b/tools/runtest.sh new file mode 100644 index 0000000..2fc4d4a --- /dev/null +++ b/tools/runtest.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +coverage run --source='.' manage.py test +nose html +open htmlcov/index.html From 1d4af5cc7cbffbba38ea9bd6ed951e6e10317f3d Mon Sep 17 00:00:00 2001 From: sxw Date: Tue, 4 Aug 2015 19:18:56 +0800 Subject: [PATCH 07/11] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BA=86windows?= =?UTF-8?q?=E4=B8=8B=E7=9A=84runserver=E5=92=8Cruntest=E8=84=9A=E6=9C=AC?= =?UTF-8?q?=20[ci=20sikp]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tools/runserver.cmd | 5 +++++ tools/runtest.cmd | 12 ++++++++++++ tools/runtest.sh | 2 +- 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 tools/runserver.cmd create mode 100644 tools/runtest.cmd diff --git a/tools/runserver.cmd b/tools/runserver.cmd new file mode 100644 index 0000000..b458e55 --- /dev/null +++ b/tools/runserver.cmd @@ -0,0 +1,5 @@ +@echo off +python manage.py runserver +cls +cd.. +python manage.py runserver \ No newline at end of file diff --git a/tools/runtest.cmd b/tools/runtest.cmd new file mode 100644 index 0000000..e6d9ad7 --- /dev/null +++ b/tools/runtest.cmd @@ -0,0 +1,12 @@ +@echo off +coverage run --source='.' manage.py test +coverage html +cd htmlcov +index.html +cls +cd.. +coverage run --source='.' manage.py test +coverage html +cd htmlcov +index.html + diff --git a/tools/runtest.sh b/tools/runtest.sh index 2fc4d4a..87399cc 100644 --- a/tools/runtest.sh +++ b/tools/runtest.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash coverage run --source='.' manage.py test -nose html +coverage html open htmlcov/index.html From 0b55f6bbf79bf8f66c1ea81931165c5e3464feef Mon Sep 17 00:00:00 2001 From: sxw Date: Tue, 4 Aug 2015 19:54:44 +0800 Subject: [PATCH 08/11] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=86=E9=87=8D?= =?UTF-8?q?=E5=A4=8D=E5=AF=86=E7=A0=81=E9=AA=8C=E8=AF=81=E7=9A=84js?= =?UTF-8?q?=EF=BC=8C=E7=B2=BE=E7=AE=80=E4=BB=A3=E7=A0=81=E9=87=8F=EF=BC=8C?= =?UTF-8?q?=E5=87=8F=E5=B0=91=E4=BA=86=E9=87=8D=E5=A4=8D=E7=9A=84=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=EF=BC=8C=E5=87=8F=E5=B0=91=E4=BA=86valuedator?= =?UTF-8?q?=E4=B8=ADconfirm=E7=9A=84=E5=8F=82=E6=95=B0=20[ci=20skip]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/js/app/oj/account/change_password.js | 23 +------------------ static/src/js/app/oj/account/register.js | 23 ++----------------- .../lib/formValidation/validator/confirm.js | 10 ++++---- .../formValidation/validator/usernameCheck.js | 21 ++++++----------- static/src/js/utils/validation.js | 1 - 5 files changed, 14 insertions(+), 64 deletions(-) diff --git a/static/src/js/app/oj/account/change_password.js b/static/src/js/app/oj/account/change_password.js index ff9bf74..e3e907f 100644 --- a/static/src/js/app/oj/account/change_password.js +++ b/static/src/js/app/oj/account/change_password.js @@ -1,7 +1,4 @@ - require(["jquery", "bs_alert", "csrf", "validation"], function($, bs_alert, csrfHeader){ - - $("#change_password-form").formValidation({ framework: "bootstrap", fields: { @@ -28,20 +25,11 @@ require(["jquery", "bs_alert", "csrf", "validation"], function($, bs_alert, csrf min: 6, max: 30, message: '密码长度必须在6到30位之间' - }, - confirm: { - firstPassword: $("#new_password"), - secondPassword: $("#confirm_password"), - message: "两次输入的密码必须一致" } }, onSuccess: function(e, data) { - - if (!data.fv.isValidField('confirm_password')) { data.fv.revalidateField('confirm_password'); - } } - }, confirm_password: { validators: { @@ -49,17 +37,10 @@ require(["jquery", "bs_alert", "csrf", "validation"], function($, bs_alert, csrf message: "请填写确认密码" }, confirm: { - firstPassword: $("#new_password"), - secondPassword: $("#confirm_password"), + original: $("#new_password"), message: "两次输入的密码必须一致" } }, - onSuccess: function(e, data) { - - if (!data.fv.isValidField('new_password')) { - data.fv.revalidateField('new_password'); - } - } } } } @@ -83,8 +64,6 @@ require(["jquery", "bs_alert", "csrf", "validation"], function($, bs_alert, csrf bs_alert(data.data); } } - }) }); - }); \ No newline at end of file diff --git a/static/src/js/app/oj/account/register.js b/static/src/js/app/oj/account/register.js index 4baf334..e6b4deb 100644 --- a/static/src/js/app/oj/account/register.js +++ b/static/src/js/app/oj/account/register.js @@ -1,5 +1,4 @@ require(["jquery", "bs_alert", "csrf", "validation"], function($, bs_alert, csrfHeader){ - $("#register-form") .formValidation({ framework: "bootstrap", @@ -28,18 +27,10 @@ require(["jquery", "bs_alert", "csrf", "validation"], function($, bs_alert, csrf min: 6, max: 30, message: '密码长度必须在6到30位之间' - }, - confirm: { - firstPassword: $("#password"), - secondPassword: $("#confirm_password"), - message: "两次输入的密码必须一致" - } + } }, onSuccess: function(e, data) { - - if (!data.fv.isValidField('confirm_password')) { data.fv.revalidateField('confirm_password'); - } } }, real_name: { @@ -48,7 +39,6 @@ require(["jquery", "bs_alert", "csrf", "validation"], function($, bs_alert, csrf message: "请填写真实姓名" } }, - }, confirm_password: { validators: { @@ -56,18 +46,9 @@ require(["jquery", "bs_alert", "csrf", "validation"], function($, bs_alert, csrf message: "请填写确认密码" }, confirm: { - firstPassword: $("#password"), - secondPassword: $("#confirm_password"), + original: $("#password"), message: "两次输入的密码必须一致" } - - }, - - onSuccess: function(e, data) { - - if (!data.fv.isValidField('password')) { - data.fv.revalidateField('password'); - } } } } diff --git a/static/src/js/lib/formValidation/validator/confirm.js b/static/src/js/lib/formValidation/validator/confirm.js index 5d491ee..db5ad3a 100644 --- a/static/src/js/lib/formValidation/validator/confirm.js +++ b/static/src/js/lib/formValidation/validator/confirm.js @@ -22,13 +22,11 @@ } } }); - FormValidation.Validator.confirm = { - validate: function(validator, $field, options) { - if (options.firstPassword.val() == options.secondPassword.val() ||options.secondPassword.val()== '') - return true; - return false; - } + if (options.original.val() == $field.val() || $field.val()== '') + return true; + return false; + } }; })); diff --git a/static/src/js/lib/formValidation/validator/usernameCheck.js b/static/src/js/lib/formValidation/validator/usernameCheck.js index 116c1dc..36a7762 100644 --- a/static/src/js/lib/formValidation/validator/usernameCheck.js +++ b/static/src/js/lib/formValidation/validator/usernameCheck.js @@ -1,7 +1,6 @@ /** * usernameCheck validator */ - (function(root, factory) { "use strict"; @@ -13,7 +12,6 @@ // planted over the root! factory(root.jQuery, root.FormValidation); } - }(this, function ($, FormValidation, csrfHeader) { FormValidation.I18n = $.extend(true, FormValidation.I18n || {}, { 'en_US': { @@ -22,23 +20,18 @@ } } }); - FormValidation.Validator.usernameCheck = { - validate: function(validator, $field, options) { if ($field.val() == '') return true; return !$.ajax({ - async: false, - beforeSend: csrfHeader, - url: "/api/username_check/", - data: {username: $field.val()}, - dataType: "json", - method: "post", - - - }).responseJSON.data; - + async: false, + beforeSend: csrfHeader, + url: "/api/username_check/", + data: {username: $field.val()}, + dataType: "json", + method: "post", + }).responseJSON.data; } }; })); diff --git a/static/src/js/utils/validation.js b/static/src/js/utils/validation.js index 38788f7..5fe792f 100644 --- a/static/src/js/utils/validation.js +++ b/static/src/js/utils/validation.js @@ -11,5 +11,4 @@ define("validation", 'validator/confirm', 'validator/usernameCheck'], function () { - }); \ No newline at end of file From 44be61dab6b21553367ea84f60f40e31cb587bf4 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Wed, 5 Aug 2015 08:43:15 +0800 Subject: [PATCH 09/11] =?UTF-8?q?=E4=BF=AE=E6=94=B9=20runtest.sh=EF=BC=8C?= =?UTF-8?q?=E5=8F=AA=E6=9C=89=E5=9C=A8=E6=B5=8B=E8=AF=95=E6=88=90=E5=8A=9F?= =?UTF-8?q?=E7=9A=84=E6=83=85=E5=86=B5=E4=B8=8B=E6=89=8D=E8=BF=9B=E8=A1=8C?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E8=A6=86=E7=9B=96=E7=8E=87=E5=88=86=E6=9E=90?= =?UTF-8?q?=E5=92=8C=E6=89=93=E5=BC=80=E7=BB=93=E6=9E=9C=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tools/runtest.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/runtest.sh b/tools/runtest.sh index 87399cc..f41a02b 100644 --- a/tools/runtest.sh +++ b/tools/runtest.sh @@ -1,4 +1,7 @@ #!/usr/bin/env bash coverage run --source='.' manage.py test -coverage html -open htmlcov/index.html +test_result=$? +if [ "$test_result" -eq 0 ];then + coverage html + open htmlcov/index.html +fi From 8a6093d6457c1e5ddbeacf87575a95fa4ce1d222 Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Wed, 5 Aug 2015 08:44:28 +0800 Subject: [PATCH 10/11] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E9=80=9A=E7=94=A8?= =?UTF-8?q?=E5=88=86=E9=A1=B5=E5=87=BD=E6=95=B0=E5=92=8C=E5=AF=B9=E5=BA=94?= =?UTF-8?q?=E7=9A=84=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- oj/settings.py | 1 + utils/shortcuts.py | 49 ++++++++++++++++++++++++++++++++++- utils/test_urls.py | 9 +++++++ utils/tests.py | 64 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 utils/test_urls.py create mode 100644 utils/tests.py diff --git a/oj/settings.py b/oj/settings.py index db9ea8f..793f605 100644 --- a/oj/settings.py +++ b/oj/settings.py @@ -47,6 +47,7 @@ INSTALLED_APPS = ( 'django.contrib.staticfiles', 'account', + 'utils', 'rest_framework', 'rest_framework_swagger', diff --git a/utils/shortcuts.py b/utils/shortcuts.py index bd5f286..3d37063 100644 --- a/utils/shortcuts.py +++ b/utils/shortcuts.py @@ -1,4 +1,7 @@ # coding=utf-8 +from django.core.paginator import Paginator + +from rest_framework import pagination from rest_framework.response import Response @@ -11,4 +14,48 @@ def serializer_invalid_response(serializer): def success_response(data): - return Response(data={"code": 0, "data": data}) \ No newline at end of file + return Response(data={"code": 0, "data": data}) + + +def paginate(request, query_set, object_serializer): + """ + 用于分页的函数 + :param query_set 数据库查询结果 + :param object_serializer: 序列化单个object的serializer + :return response + """ + need_paginate = request.GET.get("paging", None) + # 如果请求的参数里面没有paging=true的话 就返回全部数据 + if need_paginate != "true": + return success_response(data=object_serializer(query_set, many=True).data) + + page_size = request.GET.get("page_size", None) + if not page_size: + return error_response(u"参数错误") + + try: + page_size = int(page_size) + except Exception: + return error_response(u"参数错误") + + paginator = Paginator(query_set, page_size) + page = request.GET.get("page", None) + + try: + current_page = paginator.page(page) + except Exception: + return error_response(u"参数错误") + + data = {"results": object_serializer(current_page, many=True).data, "previous_page": None, "next_page": None} + + try: + data["previous_page"] = current_page.previous_page_number() + except Exception: + pass + + try: + data["next_page"] = current_page.next_page_number() + except Exception: + pass + + return success_response(data) \ No newline at end of file diff --git a/utils/test_urls.py b/utils/test_urls.py new file mode 100644 index 0000000..0500d16 --- /dev/null +++ b/utils/test_urls.py @@ -0,0 +1,9 @@ +# coding=utf-8 +from django.conf.urls import include, url + + + +urlpatterns = [ + url(r'^paginate_test/$', "utils.tests.pagination_test_func"), +] + diff --git a/utils/tests.py b/utils/tests.py new file mode 100644 index 0000000..9ab31f9 --- /dev/null +++ b/utils/tests.py @@ -0,0 +1,64 @@ +# coding=utf-8 +from rest_framework.test import APIClient, APITestCase +from rest_framework import serializers +from rest_framework.decorators import api_view + +from account.models import User +from .shortcuts import paginate + + +class PaginationTestSerialiser(serializers.Serializer): + username = serializers.CharField(max_length=100) + + +@api_view(["GET"]) +def pagination_test_func(request): + return paginate(request, User.objects.all(), PaginationTestSerialiser) + + +class PaginatorTest(APITestCase): + urls = "utils.test_urls" + + def setUp(self): + self.client = APIClient() + self.url = "/paginate_test/" + User.objects.create(username="test1") + User.objects.create(username="test2") + + def test_no_paginate(self): + response = self.client.get(self.url) + self.assertEqual(response.data["code"], 0) + self.assertNotIn("next_page", response.data["data"]) + self.assertNotIn("previous_page", response.data["data"]) + + def test_error_parameter(self): + response = self.client.get(self.url + "?paging=true") + self.assertEqual(response.data, {"code": 1, "data": u"参数错误"}) + + response = self.client.get(self.url + "?paging=true&limit=-1") + self.assertEqual(response.data, {"code": 1, "data": u"参数错误"}) + + response = self.client.get(self.url + "?paging=true&limit=aa") + self.assertEqual(response.data, {"code": 1, "data": u"参数错误"}) + + response = self.client.get(self.url + "?paging=true&limit=1&page_size=1&page=-1") + self.assertEqual(response.data, {"code": 1, "data": u"参数错误"}) + + response = self.client.get(self.url + "?paging=true&limit=1&page_size=aaa&page=1") + self.assertEqual(response.data, {"code": 1, "data": u"参数错误"}) + + response = self.client.get(self.url + "?paging=true&limit=1&page_size=1&page=aaa") + self.assertEqual(response.data, {"code": 1, "data": u"参数错误"}) + + def test_correct_paginate(self): + response = self.client.get(self.url + "?paging=true&limit=1&page_size=1&page=1") + self.assertEqual(response.data["code"], 0) + self.assertEqual(response.data["data"]["previous_page"], None) + self.assertEqual(response.data["data"]["next_page"], 2) + self.assertEqual(len(response.data["data"]["results"]), 1) + + response = self.client.get(self.url + "?paging=true&limit=1&page_size=2&page=1") + self.assertEqual(response.data["code"], 0) + self.assertEqual(response.data["data"]["previous_page"], None) + self.assertEqual(response.data["data"]["next_page"], None) + self.assertEqual(len(response.data["data"]["results"]), 2) From 5558600792c66135e97d349e1ee2d88a1324fb4b Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Wed, 5 Aug 2015 08:53:39 +0800 Subject: [PATCH 11/11] =?UTF-8?q?=E8=A1=A5=E5=85=85=E9=80=9A=E7=94=A8?= =?UTF-8?q?=E5=88=86=E9=A1=B5=E5=87=BD=E6=95=B0=E7=9A=84=E6=B3=A8=E9=87=8A?= =?UTF-8?q?=E5=92=8C=E7=94=A8=E6=B3=95=EF=BC=9B=E4=BF=AE=E6=94=B9=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E7=9A=84=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utils/shortcuts.py | 26 +++++++++++++++++++++++++- utils/tests.py | 10 +++++----- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/utils/shortcuts.py b/utils/shortcuts.py index 3d37063..852622f 100644 --- a/utils/shortcuts.py +++ b/utils/shortcuts.py @@ -1,7 +1,6 @@ # coding=utf-8 from django.core.paginator import Paginator -from rest_framework import pagination from rest_framework.response import Response @@ -20,6 +19,31 @@ def success_response(data): def paginate(request, query_set, object_serializer): """ 用于分页的函数 + 如果 url 里面不含有paging=true,那么将返回全部数据。类似 + [ + { + "username": "1111111", + "password": "123456" + } + ] + 如果 url 中有 paging=true 的参数, + 然后还需要读取其余的两个参数,page=[int],需要的页码,p + age_size=[int],一页的数据条数 + 参数错误的时候,返回{"code": 1, "data": u"参数错误"} + 返回的数据格式 + { + "code": 0, + "data": { + "previous_page": null, + "results": [ + { + "username": "1111111", + "password": "123456" + } + ], + "next_page": 2 + } + } :param query_set 数据库查询结果 :param object_serializer: 序列化单个object的serializer :return response diff --git a/utils/tests.py b/utils/tests.py index 9ab31f9..519870c 100644 --- a/utils/tests.py +++ b/utils/tests.py @@ -35,19 +35,19 @@ class PaginatorTest(APITestCase): response = self.client.get(self.url + "?paging=true") self.assertEqual(response.data, {"code": 1, "data": u"参数错误"}) - response = self.client.get(self.url + "?paging=true&limit=-1") + response = self.client.get(self.url + "?paging=true&page_size=-1") self.assertEqual(response.data, {"code": 1, "data": u"参数错误"}) - response = self.client.get(self.url + "?paging=true&limit=aa") + response = self.client.get(self.url + "?paging=true&page_size=aa") self.assertEqual(response.data, {"code": 1, "data": u"参数错误"}) - response = self.client.get(self.url + "?paging=true&limit=1&page_size=1&page=-1") + response = self.client.get(self.url + "?paging=true&page_size=1&page=-1") self.assertEqual(response.data, {"code": 1, "data": u"参数错误"}) - response = self.client.get(self.url + "?paging=true&limit=1&page_size=aaa&page=1") + response = self.client.get(self.url + "?paging=true&page_size=aaa&page=1") self.assertEqual(response.data, {"code": 1, "data": u"参数错误"}) - response = self.client.get(self.url + "?paging=true&limit=1&page_size=1&page=aaa") + response = self.client.get(self.url + "?paging=true&page_size=1&page=aaa") self.assertEqual(response.data, {"code": 1, "data": u"参数错误"}) def test_correct_paginate(self):