diff --git a/account/decorators.py b/account/decorators.py index 6b108960..01cdd68f 100644 --- a/account/decorators.py +++ b/account/decorators.py @@ -20,5 +20,13 @@ def login_required(func): return check -def admin_required(): - pass +def admin_required(func): + def check(*args, **kwargs): + request = args[-1] + if request.user.is_authenticated() and request.user.admin_type: + return func(*args, **kwargs) + if request.is_ajax(): + return error_response(u"需要管理员权限") + else: + return render(request, "utils/error.html", {"error": "需要管理员权限"}) + return check diff --git a/account/models.py b/account/models.py index 1f02eef9..7c5afb96 100644 --- a/account/models.py +++ b/account/models.py @@ -21,7 +21,8 @@ class User(AbstractBaseUser): real_name = models.CharField(max_length=30, blank=True, null=True) # 用户邮箱 email = models.EmailField(max_length=254, blank=True, null=True) - admin_group = models.ForeignKey(AdminGroup, null=True, on_delete=models.SET_NULL) + # 0代表不是管理员 1是普通管理员 2是超级管理员 + admin_type = models.IntegerField(default=0) USERNAME_FIELD = 'username' REQUIRED_FIELDS = [] diff --git a/account/test_urls.py b/account/test_urls.py index 40667215..9757d901 100644 --- a/account/test_urls.py +++ b/account/test_urls.py @@ -1,12 +1,18 @@ # coding=utf-8 from django.conf.urls import include, url -from .tests import LoginRequiredCBVTestWithArgs, LoginRequiredCBVTestWithoutArgs +from .tests import (LoginRequiredCBVTestWithArgs, LoginRequiredCBVTestWithoutArgs, + AdminRequiredCBVTestWithArgs, AdminRequiredCBVTestWithoutArgs) urlpatterns = [ - url(r'^test/fbv/1/$', "account.tests.login_required_FBV_test_without_args"), - url(r'^test/fbv/(?P\d+)/$', "account.tests.login_required_FBC_test_with_args"), - url(r'^test/cbv/1/$', LoginRequiredCBVTestWithoutArgs.as_view()), - url(r'^test/cbv/(?P\d+)/$', LoginRequiredCBVTestWithArgs.as_view()), + url(r'^login_required_test/fbv/1/$', "account.tests.login_required_FBV_test_without_args"), + url(r'^login_required_test/fbv/(?P\d+)/$', "account.tests.login_required_FBC_test_with_args"), + url(r'^login_required_test/cbv/1/$', LoginRequiredCBVTestWithoutArgs.as_view()), + url(r'^login_required_test/cbv/(?P\d+)/$', LoginRequiredCBVTestWithArgs.as_view()), + + url(r'^admin_required_test/fbv/1/$', "account.tests.admin_required_FBV_test_without_args"), + url(r'^admin_required_test/fbv/(?P\d+)/$', "account.tests.admin_required_FBC_test_with_args"), + url(r'^admin_required_test/cbv/1/$', AdminRequiredCBVTestWithoutArgs.as_view()), + url(r'^admin_required_test/cbv/(?P\d+)/$', AdminRequiredCBVTestWithArgs.as_view()), ] diff --git a/account/tests.py b/account/tests.py index 89410da3..3529bb6e 100644 --- a/account/tests.py +++ b/account/tests.py @@ -10,7 +10,7 @@ from rest_framework.views import APIView from rest_framework.response import Response from .models import User -from .decorators import login_required +from .decorators import login_required, admin_required class UserLoginTest(TestCase): @@ -159,6 +159,7 @@ class LoginRequiredCBVTestWithoutArgs(APIView): def get(self, request): return HttpResponse("class based view login required test1") + class LoginRequiredCBVTestWithArgs(APIView): @login_required def get(self, request, problem_id): @@ -176,40 +177,113 @@ class LoginRequiredDecoratorTest(TestCase): def test_fbv_without_args(self): # 没登陆 - response = self.client.get("/test/fbv/1/") + response = self.client.get("/login_required_test/fbv/1/") self.assertTemplateUsed(response, "utils/error.html") # 登陆后 self.client.login(username="test", password="test") - response = self.client.get("/test/fbv/1/") + response = self.client.get("/login_required_test/fbv/1/") self.assertEqual(response.content, "function based view test1") def test_fbv_with_args(self): # 没登陆 - response = self.client.get("/test/fbv/1024/") + response = self.client.get("/login_required_test/fbv/1024/") self.assertTemplateUsed(response, "utils/error.html") # 登陆后 self.client.login(username="test", password="test") - response = self.client.get("/test/fbv/1024/") + response = self.client.get("/login_required_test/fbv/1024/") self.assertEqual(response.content, "1024") def test_cbv_without_args(self): # 没登陆 - response = self.client.get("/test/cbv/1/") + response = self.client.get("/login_required_test/cbv/1/") self.assertTemplateUsed(response, "utils/error.html") # 登陆后 self.client.login(username="test", password="test") - response = self.client.get("/test/cbv/1/") + response = self.client.get("/login_required_test/cbv/1/") self.assertEqual(response.content, "class based view login required test1") def test_cbv_with_args(self): # 没登陆 - response = self.client.get("/test/cbv/1024/", HTTP_X_REQUESTED_WITH='XMLHttpRequest') + response = self.client.get("/login_required_test/cbv/1024/", HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertEqual(json.loads(response.content), {"code": 1, "data": u"请先登录"}) # 登陆后 self.client.login(username="test", password="test") - response = self.client.get("/test/cbv/1024/") + response = self.client.get("/login_required_test/cbv/1024/") + self.assertEqual(response.content, "1024") + + +@admin_required +def admin_required_FBV_test_without_args(request): + return HttpResponse("function based view test1") + + +@admin_required +def admin_required_FBC_test_with_args(request, problem_id): + return HttpResponse(problem_id) + + +class AdminRequiredCBVTestWithoutArgs(APIView): + @admin_required + def get(self, request): + return HttpResponse("class based view login required test1") + + +class AdminRequiredCBVTestWithArgs(APIView): + @admin_required + def get(self, request, problem_id): + return HttpResponse(problem_id) + + +class AdminRequiredDecoratorTest(TestCase): + urls = 'account.test_urls' + + def setUp(self): + self.client = Client() + user = User.objects.create(username="test") + user.admin_type = 1 + user.set_password("test") + user.save() + + def test_fbv_without_args(self): + # 没登陆 + response = self.client.get("/admin_required_test/fbv/1/") + self.assertTemplateUsed(response, "utils/error.html") + + # 登陆后 + self.client.login(username="test", password="test") + response = self.client.get("/admin_required_test/fbv/1/") + self.assertEqual(response.content, "function based view test1") + + def test_fbv_with_args(self): + # 没登陆 + response = self.client.get("/admin_required_test/fbv/1024/") + self.assertTemplateUsed(response, "utils/error.html") + + # 登陆后 + self.client.login(username="test", password="test") + response = self.client.get("/admin_required_test/fbv/1024/") + self.assertEqual(response.content, "1024") + + def test_cbv_without_args(self): + # 没登陆 + response = self.client.get("/admin_required_test/cbv/1/") + self.assertTemplateUsed(response, "utils/error.html") + + # 登陆后 + self.client.login(username="test", password="test") + response = self.client.get("/admin_required_test/cbv/1/") + self.assertEqual(response.content, "class based view login required test1") + + def test_cbv_with_args(self): + # 没登陆 + response = self.client.get("/admin_required_test/cbv/1024/", HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(json.loads(response.content), {"code": 1, "data": u"需要管理员权限"}) + + # 登陆后 + self.client.login(username="test", password="test") + response = self.client.get("/admin_required_test/cbv/1024/") self.assertEqual(response.content, "1024") diff --git a/static/src/js/app/oj/account/change_password.js b/static/src/js/app/oj/account/change_password.js index e3e907fa..c76dd9d7 100644 --- a/static/src/js/app/oj/account/change_password.js +++ b/static/src/js/app/oj/account/change_password.js @@ -1,4 +1,4 @@ -require(["jquery", "bs_alert", "csrf", "validation"], function($, bs_alert, csrfHeader){ +require(["jquery", "bs_alert", "csrf", "validation"], function ($, bs_alert, csrfHeader) { $("#change_password-form").formValidation({ framework: "bootstrap", fields: { @@ -13,22 +13,22 @@ require(["jquery", "bs_alert", "csrf", "validation"], function($, bs_alert, csrf validators: { notEmpty: { message: "请填写旧密码" - } + } } }, new_password: { validators: { notEmpty: { message: "请填写新密码" - }, + }, stringLength: { min: 6, max: 30, message: '密码长度必须在6到30位之间' } }, - onSuccess: function(e, data) { - data.fv.revalidateField('confirm_password'); + onSuccess: function (e, data) { + data.fv.revalidateField('confirm_password'); } }, confirm_password: { @@ -40,27 +40,27 @@ require(["jquery", "bs_alert", "csrf", "validation"], function($, bs_alert, csrf original: $("#new_password"), message: "两次输入的密码必须一致" } - }, + } } } } - ).on('success.form.fv', function(e) { + ).on('success.form.fv', function (e) { e.preventDefault(); var username = $("#username").val(); - var new_password = $("#new_password ").val(); + 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}, + data: {username: username, new_password: new_password, old_password: password}, dataType: "json", method: "post", success: function (data) { - if(!data.code){ - window.location.href="/login/"; + if (!data.code) { + window.location.href = "/login/"; } - else{ + else { bs_alert(data.data); } } diff --git a/static/src/js/app/oj/account/login.js b/static/src/js/app/oj/account/login.js index da4416db..2ecebf73 100644 --- a/static/src/js/app/oj/account/login.js +++ b/static/src/js/app/oj/account/login.js @@ -1,6 +1,6 @@ -require(["jquery", "bs_alert", "csrf", "validation"], function($, bs_alert, csrfHeader){ +require(["jquery", "bs_alert", "csrf", "validation"], function ($, bs_alert, csrfHeader) { $("#login-form") - .formValidation({ + .formValidation({ framework: "bootstrap", fields: { username: { @@ -19,7 +19,7 @@ require(["jquery", "bs_alert", "csrf", "validation"], function($, bs_alert, csrf } } } - ).on('success.form.fv', function(e) { + ).on('success.form.fv', function (e) { e.preventDefault(); var username = $("#username").val(); var password = $("#password").val(); @@ -30,10 +30,10 @@ require(["jquery", "bs_alert", "csrf", "validation"], function($, bs_alert, csrf dataType: "json", method: "post", success: function (data) { - if(!data.code){ - window.location.href="/"; + if (!data.code) { + window.location.href = "/"; } - else{ + else { bs_alert(data.data); } } diff --git a/static/src/js/app/oj/account/register.js b/static/src/js/app/oj/account/register.js index a7a3ea12..52c3d362 100644 --- a/static/src/js/app/oj/account/register.js +++ b/static/src/js/app/oj/account/register.js @@ -1,14 +1,10 @@ -require(["jquery", "bs_alert", "csrf", "validation"], function($, bs_alert, csrfHeader){ +require(["jquery", "bs_alert", "csrf", "validation"], function ($, bs_alert, csrfHeader) { $("#register-form") - .formValidation({ + .formValidation({ framework: "bootstrap", - icon: { - valid: 'glyphicon glyphicon-ok', - invalid: 'glyphicon glyphicon-remove', - validating: 'glyphicon glyphicon-refresh' - }, fields: { username: { + trigger: 'blur', validators: { notEmpty: { message: "请填写用户名" @@ -29,23 +25,23 @@ require(["jquery", "bs_alert", "csrf", "validation"], function($, bs_alert, csrf validators: { notEmpty: { message: "请填写密码" - }, - stringLength: { - min: 6, - max: 30, - message: '密码长度必须在6到30位之间' - } + }, + stringLength: { + min: 6, + max: 30, + message: '密码长度必须在6到30位之间' + } }, - onSuccess: function(e, data) { - data.fv.revalidateField('confirm_password'); + onSuccess: function (e, data) { + data.fv.revalidateField('confirm_password'); } }, real_name: { validators: { notEmpty: { message: "请填写真实姓名" - } - }, + } + } }, confirm_password: { validators: { @@ -59,6 +55,7 @@ require(["jquery", "bs_alert", "csrf", "validation"], function($, bs_alert, csrf } }, email: { + trigger: 'blur', validators: { notEmpty: { message: "请填写电子邮箱邮箱地址" @@ -75,22 +72,23 @@ require(["jquery", "bs_alert", "csrf", "validation"], function($, bs_alert, csrf } } } - ).on('success.form.fv', function(e) { + ).on('success.form.fv', function (e) { e.preventDefault(); var username = $("#username").val(); var real_name = $("#real_name").val(); var password = $("#password").val(); + var email = $("#email").val(); $.ajax({ beforeSend: csrfHeader, url: "/api/register/", - data: {username: username, real_name: real_name, password: password}, + data: {username: username, real_name: real_name, password: password, email: email}, dataType: "json", method: "post", success: function (data) { - if(!data.code){ - window.location.href="/login/"; + if (!data.code) { + window.location.href = "/login/"; } - else{ + else { bs_alert(data.data); } }