From b43970d0582591aba856b129ddd1870dd35ad9ce Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Wed, 14 Oct 2015 09:57:43 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20account=20=E9=87=8C?= =?UTF-8?q?=E9=9D=A2=E5=A4=B1=E8=B4=A5=E7=9A=84=E6=B5=8B=E8=AF=95=EF=BC=9B?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=9D=83=E9=99=90=20decorator=20=E7=9A=84?= =?UTF-8?q?=E5=86=99=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- account/decorators.py | 80 +++++------- account/serializers.py | 8 +- account/test_urls.py | 9 +- account/tests.py | 289 +++++++++++++++++++++++++++++------------ 4 files changed, 253 insertions(+), 133 deletions(-) diff --git a/account/decorators.py b/account/decorators.py index 1181c6a..2646c02 100644 --- a/account/decorators.py +++ b/account/decorators.py @@ -1,58 +1,48 @@ # coding=utf-8 +import functools from functools import wraps -from django.http import HttpResponse, HttpResponseRedirect -from django.shortcuts import render -from utils.shortcuts import error_response, error_page -from .models import User, SUPER_ADMIN +from django.http import HttpResponseRedirect + +from utils.shortcuts import error_response +from .models import SUPER_ADMIN, ADMIN -def login_required(func): - @wraps(func) - def check(*args, **kwargs): - # 在class based views 里面,args 有两个元素,一个是self, 第二个才是request, - # 在function based views 里面,args 只有request 一个参数 +class BasePermissionDecorator(object): + def __init__(self, func): + self.func = func + + def __get__(self, obj, obj_type): + return functools.partial(self.__call__, obj) + + def __call__(self, *args, **kwargs): if len(args) == 2: - request = args[-1] + self.request = args[1] else: - request = args[0] - if request.user.is_authenticated(): - return func(*args, **kwargs) - if request.is_ajax(): - return error_response(u"请先登录") + self.request = args[0] + + if self.check_permission(): + return self.func(*args, **kwargs) else: - return HttpResponseRedirect("/login/") - return check + if self.request.is_ajax(): + return error_response(u"请先登录") + else: + return HttpResponseRedirect("/login/") + + def check_permission(self): + raise NotImplementedError() -def admin_required(func): - @wraps(func) - def check(*args, **kwargs): - if len(args) == 2: - request = args[-1] - else: - request = args[0] - if request.user.is_authenticated() and request.user.admin_type: - return func(*args, **kwargs) - if request.is_ajax(): - return error_response(u"需要管理员权限") - else: - return error_page(request, u"需要管理员权限,如果没有登录,请先登录") - return check +class login_required(BasePermissionDecorator): + def check_permission(self): + return self.request.user.is_authenticated() -def super_admin_required(func): - @wraps(func) - def check(*args, **kwargs): - if len(args) == 2: - request = args[-1] - else: - request = args[0] - if request.user.is_authenticated() and request.user.admin_type == SUPER_ADMIN: - return func(*args, **kwargs) - if request.is_ajax(): - return error_response(u"需要超级管理员权限") - else: - return error_page(request, u"需要超级管理员权限") +class super_admin_required(BasePermissionDecorator): + def check_permission(self): + return self.request.user.is_authenticated() and self.request.user.admin_type == SUPER_ADMIN - return check \ No newline at end of file + +class admin_required(BasePermissionDecorator): + def check_permission(self): + return self.request.user.is_authenticated() and self.request.user.admin_type in [SUPER_ADMIN, ADMIN] \ No newline at end of file diff --git a/account/serializers.py b/account/serializers.py index 528edc7..13f3e24 100644 --- a/account/serializers.py +++ b/account/serializers.py @@ -7,7 +7,7 @@ from .models import User class UserLoginSerializer(serializers.Serializer): username = serializers.CharField(max_length=30) password = serializers.CharField(max_length=30) - captcha = serializers.CharField(required=False, min_length=4, max_length=4) + captcha = serializers.CharField(min_length=4, max_length=4) class UsernameCheckSerializer(serializers.Serializer): @@ -51,4 +51,10 @@ 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) + + +class ResetPasswordSerializer(serializers.Serializer): + token = serializers.CharField(min_length=1, max_length=40) + password = serializers.CharField(min_length=6, max_length=30) captcha = serializers.CharField(max_length=4, min_length=4) \ No newline at end of file diff --git a/account/test_urls.py b/account/test_urls.py index 5d2bdcc..224ee63 100644 --- a/account/test_urls.py +++ b/account/test_urls.py @@ -3,7 +3,8 @@ from django.conf.urls import include, url from django.views.generic import TemplateView from .tests import (LoginRequiredCBVTestWithArgs, LoginRequiredCBVTestWithoutArgs, - AdminRequiredCBVTestWithArgs, AdminRequiredCBVTestWithoutArgs) + AdminRequiredCBVTestWithArgs, AdminRequiredCBVTestWithoutArgs, + SuperAdminRequiredCBVTestWithArgs, SuperAdminRequiredCBVTestWithoutArgs) urlpatterns = [ @@ -16,5 +17,11 @@ urlpatterns = [ 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()), + + url(r'^super_admin_required_test/fbv/1/$', "account.tests.super_admin_required_FBV_test_without_args"), + url(r'^super_admin_required_test/fbv/(?P\d+)/$', "account.tests.super_admin_required_FBC_test_with_args"), + url(r'^super_admin_required_test/cbv/1/$', SuperAdminRequiredCBVTestWithoutArgs.as_view()), + url(r'^super_admin_required_test/cbv/(?P\d+)/$', SuperAdminRequiredCBVTestWithArgs.as_view()), + url(r'^login/$', TemplateView.as_view(template_name="oj/account/login.html"), name="user_login_page"), ] diff --git a/account/tests.py b/account/tests.py index d0adf8a..968b4c2 100644 --- a/account/tests.py +++ b/account/tests.py @@ -1,17 +1,16 @@ # coding=utf-8 import json +import time from django.core.urlresolvers import reverse from django.test import TestCase, Client from django.http import HttpResponse from django.contrib import auth - from rest_framework.test import APITestCase, APIClient from rest_framework.views import APIView -from rest_framework.response import Response -from .models import User, SUPER_ADMIN -from .decorators import login_required, admin_required +from .models import User, SUPER_ADMIN, REGULAR_USER, ADMIN +from .decorators import login_required, admin_required, super_admin_required class UserLoginTest(TestCase): @@ -21,26 +20,44 @@ class UserLoginTest(TestCase): self.assertTemplateUsed(response, "oj/account/login.html") +def create_user(username="test", real_name="test_real_name", email="test@qq.com", + password="111111", admin_type=REGULAR_USER): + user = User.objects.create(username=username, real_name=real_name, email=email, admin_type=admin_type) + user.set_password(password) + user.save() + return user + + +def set_captcha(session): + session["_django_captcha_key"] = "aaaa" + session["_django_captcha_expires_time"] = time.time() + 10000 + session.save() + + class UserLoginAPITest(APITestCase): def setUp(self): self.client = APIClient() self.url = reverse("user_login_api") - user = User.objects.create(username="test") - user.set_password("test") - user.save() + self.user = create_user() + set_captcha(self.client.session) def test_invalid_data(self): data = {"username": "test"} response = self.client.post(self.url, data=data) self.assertEqual(response.data["code"], 1) + def test_captcha(self): + error_data = {"username": "test", "password": "test11", "captcha": "1111"} + response = self.client.post(self.url, data=error_data) + self.assertEqual(response.data, {"code": 1, "data": u"验证码错误"}) + def test_error_username_or_password(self): - error_data = {"username": "test", "password": "test11"} + error_data = {"username": "test", "password": "test11", "captcha": "aaaa"} response = self.client.post(self.url, data=error_data) self.assertEqual(response.data, {"code": 1, "data": u"用户名或密码错误"}) - def test_success_login(self): - data = {"username": "test", "password": "test"} + def test_login_successfully(self): + data = {"username": "test", "password": "111111", "captcha": "aaaa"} response = self.client.post(self.url, data=data) self.assertEqual(response.data, {"code": 0, "data": u"登录成功"}) @@ -49,69 +66,75 @@ class UsernameCheckTest(APITestCase): def setUp(self): self.client = APIClient() self.url = reverse("username_check_api") - User.objects.create(username="testtest") + create_user() def test_invalid_data(self): - response = self.client.post(self.url, data={"username111": "testtest"}) - self.assertEqual(response.data["code"], 1) + response = self.client.get(self.url, data={"username111": "testtest"}) + self.assertEqual(response.status_code, 200) def test_username_exists(self): - response = self.client.post(self.url, data={"username": "testtest"}) - self.assertEqual(response.data, {"code": 0, "data": True}) + response = self.client.get(self.url, data={"username": "test"}) + self.assertEqual(response.status_code, 400) def test_username_does_not_exist(self): - response = self.client.post(self.url, data={"username": "testtest123"}) - self.assertEqual(response.data, {"code": 0, "data": False}) + response = self.client.get(self.url, data={"username": "testtest123"}) + self.assertEqual(response.status_code, 200) class EmailCheckTest(APITestCase): def setUp(self): self.client = APIClient() self.url = reverse("email_check_api") - User.objects.create(email="11@qq.com") + create_user() def test_invalid_data(self): - response = self.client.post(self.url, data={"email000": "11@qq.com"}) - self.assertEqual(response.data["code"], 1) + response = self.client.get(self.url, data={"email000": "11@qq.com"}) + self.assertEqual(response.status_code, 200) def test_email_exists(self): - response = self.client.post(self.url, data={"email": "11@qq.com"}) - self.assertEqual(response.data, {"code": 0, "data": True}) + response = self.client.get(self.url, data={"email": "test@qq.com"}) + self.assertEqual(response.status_code, 400) def test_email_does_not_exist(self): - response = self.client.post(self.url, data={"email": "33@qq.com"}) - self.assertEqual(response.data, {"code": 0, "data": False}) + response = self.client.get(self.url, data={"email": "33testtest@qq.com"}) + self.assertEqual(response.status_code, 200) class UserRegisterAPITest(APITestCase): def setUp(self): self.client = APIClient() self.url = reverse("user_register_api") + set_captcha(self.client.session) def test_invalid_data(self): data = {"username": "test", "real_name": "TT"} response = self.client.post(self.url, data=data) self.assertEqual(response.data["code"], 1) + def test_captcha(self): + data = {"username": "test", "real_name": "TT", "password": "qqqqqq", "email": "6060@qq.com", "captcha": "bbaa"} + response = self.client.post(self.url, data=data) + self.assertEqual(response.data, {"code": 1, "data": u"验证码错误"}) + def test_short_password(self): - data = {"username": "test", "real_name": "TT", "password": "qq", "email": "6060@qq.com"} + data = {"username": "test", "real_name": "TT", "password": "qq", "email": "6060@qq.com", "captcha": "aaaa"} response = self.client.post(self.url, data=data) self.assertEqual(response.data["code"], 1) def test_same_username(self): - User.objects.create(username="aa") - data = {"username": "aa", "real_name": "ww", "password": "zzzzzzz", "email": "6060@qq.com"} + create_user() + data = {"username": "test", "real_name": "ww", "password": "zzzzzzz", "email": "606fds0@qq.com", "captcha": "aaaa"} response = self.client.post(self.url, data=data) self.assertEqual(response.data, {"code": 1, "data": u"用户名已存在"}) def test_same_email(self): - User.objects.create(username="bb", email="8080@qq.com") - data = {"username": "aa", "real_name": "ww", "password": "zzzzzzz", "email": "8080@qq.com"} + create_user(username="test1", email="test1@qq.com") + data = {"username": "aa", "real_name": "ww", "password": "zzzzzzz", "email": "test1@qq.com", "captcha": "aaaa"} response = self.client.post(self.url, data=data) self.assertEqual(response.data, {"code": 1, "data": u"该邮箱已被注册,请换其他邮箱进行注册"}) - def test_success_email(self): - data = {"username": "cc", "real_name": "dd", "password": "xxxxxx", "email": "9090@qq.com"} + def test_register_successfully(self): + data = {"username": "cc", "real_name": "dd", "password": "xxxxxx", "email": "9090@qq.com", "captcha": "aaaa"} response = self.client.post(self.url, data=data) self.assertEqual(response.data, {"code": 0, "data": u"注册成功!"}) @@ -120,18 +143,27 @@ class UserChangePasswordAPITest(APITestCase): def setUp(self): self.client = APIClient() self.url = reverse("user_change_password_api") - user = User.objects.create(username="test") - user.set_password("aaabbb") - user.save() - self.client.login(username="test",password="aaabbb") + create_user() + self.client.login(username="test",password="111111") + set_captcha(self.client.session) + + def test_captcha(self): + data = {"old_password": "aaaccc", "new_password": "aaaddd", "captcha": "abba"} + response = self.client.post(self.url, data=data) + self.assertEqual(response.data, {"code": 1, "data": u"验证码错误"}) + + def test_invalid_data(self): + data = {"new_password": "aaaddd", "captcha": "aaaa"} + response = self.client.post(self.url, data=data) + self.assertEqual(response.data["code"], 1) def test_error_old_password(self): - data = {"old_password": "aaaccc", "new_password": "aaaddd"} + data = {"old_password": "aaaccc", "new_password": "aaaddd", "captcha": "aaaa"} response = self.client.post(self.url, data=data) self.assertEqual(response.data, {"code": 1, "data": u"密码不正确,请重新修改!"}) - def test_success_change_password(self): - data = {"username": "test", "old_password": "aaabbb", "new_password": "aaaccc"} + def test_change_password_successfully(self): + data = {"old_password": "111111", "new_password": "aaaccc", "captcha": "aaaa"} response = self.client.post(self.url, data=data) self.assertEqual(response.data, {"code": 0, "data": u"用户密码修改成功!"}) @@ -140,81 +172,82 @@ class UserAdminAPITest(APITestCase): def setUp(self): self.client = APIClient() self.url = reverse("user_admin_api") - self.user1 = User.objects.create(username="testx", real_name="xx", admin_type=SUPER_ADMIN) - self.user1.set_password("testxx") - self.user1.save() - self.user = User.objects.create(username="testy", real_name="yy", admin_type=SUPER_ADMIN) - self.user.set_password("testyy") - self.user.save() - self.client.login(username="testx", password="testxx") + self.user = create_user(admin_type=SUPER_ADMIN) + self.client.login(username="test", password="111111") - # 以下是编辑用户的测试 def test_success_get_data(self): self.assertEqual(self.client.get(self.url).data["code"], 0) + def test_super_admin_required(self): + create_user(username="test1", email="test1@qq.com", admin_type=ADMIN) + self.client.login(username="test1", password="111111") + + self.assertEqual(json.loads(self.client.get(self.url, HTTP_X_REQUESTED_WITH="XMLHttpRequest").content), + {"code": 1, "data": u"请先登录"}) + self.assertEqual(json.loads(self.client.put(self.url, HTTP_X_REQUESTED_WITH="XMLHttpRequest").content), + {"code": 1, "data": u"请先登录"}) + + # 这个拦截操作其实是 Middleware 完成的 + create_user(username="test2", email="test2@qq.com") + self.client.login(username="test2", password="111111") + self.assertEqual(json.loads(self.client.get(self.url, HTTP_X_REQUESTED_WITH="XMLHttpRequest").content), + {"code": 1, "data": u"请先登录"}) + self.assertEqual(json.loads(self.client.put(self.url, HTTP_X_REQUESTED_WITH="XMLHttpRequest").content), + {"code": 1, "data": u"请先登录"}) + def test_put_invalid_data(self): - data = {"username": "test", "password": "testaa", "email": "60@qq.com", "admin_type": "2"} + data = {"username": "test", "password": "testaa"} response = self.client.put(self.url, data=data) self.assertEqual(response.data["code"], 1) def test_user_does_not_exist(self): - data = {"id": 3, "username": "test0", "real_name": "test00", + data = {"id": 8888, "username": "test0", "real_name": "test00", "password": "testaa", "email": "60@qq.com", "admin_type": "2"} response = self.client.put(self.url, data=data) self.assertEqual(response.data, {"code": 1, "data": u"该用户不存在!"}) def test_username_exists(self): - data = {"id": self.user.id, "username": "testx", "real_name": "test00", + create_user(username="test1", email="test1@qq.com") + data = {"id": self.user.id, "username": "test1", "real_name": "test00", "password": "testaa", "email": "60@qq.com", "admin_type": "2"} response = self.client.put(self.url, data=data) self.assertEqual(response.data, {"code": 1, "data": u"昵称已经存在"}) - def test_user_edit_not_password_successfully(self): - data = {"id": self.user.id, "username": "test0", "real_name": "test00", + def test_edit_user_without_changing_password(self): + data = {"id": self.user.id, "username": "test2", "real_name": "test00", "email": "60@qq.com", "admin_type": "2"} response = self.client.put(self.url, data=data) self.assertEqual(response.data["code"], 0) - def test_user_edit_change_password_successfully(self): - data = {"id": self.user.id, "username": "test0", "real_name": "test00", "password": "111111", + def test_user_edit_with_changing_password(self): + data = {"id": self.user.id, "username": "test", "real_name": "test00", "password": "111111", "email": "60@qq.com", "admin_type": "2"} response = self.client.put(self.url, data=data) self.assertEqual(response.data["code"], 0) - self.assertIsNotNone(auth.authenticate(username="test0", password="111111")) + self.assertIsNotNone(auth.authenticate(username="test", password="111111")) + + def test_search_user(self): + r = self.assertEqual(self.client.get(self.url + "?keyword=11").status_code, 200) def test_error_admin_type(self): response = self.client.get(self.url + "?admin_type=error") self.assertEqual(response.data, {"code": 1, "data": u"参数错误"}) - # 以下是用户分页的测试 - def test_query_by_keyword(self): - user1 = User.objects.create(username="test1", real_name="aa") - user1.set_password("testaa") - user1.save() - - user2 = User.objects.create(username="test2", real_name="bb") - user2.set_password("testbb") - user2.save() - - user3 = User.objects.create(username="test3", real_name="cc") - user3.set_password("testcc") - user3.save() - - response = self.client.get(self.url + "?keyword=test1") - self.assertEqual(response.data["code"], 0) - class UserInfoAPITest(APITestCase): def setUp(self): self.client = APIClient() self.url = reverse('user_info_api') - user = User.objects.create(username="test1", real_name="aa") - user.set_password("testaa") - user.save() + self.user = create_user() def test_get_data_successfully(self): - self.client.login(username="test1", password="testaa") - self.assertEqual(self.client.get(self.url).data["code"], 0) + self.client.login(username="test", password="111111") + data = self.client.get(self.url).data + self.assertEqual(data["code"], 0) + self.assertEqual(data["data"]["username"], self.user.username) + + def test_get_data_without_logging_in(self): + self.assertEqual(self.client.get(self.url, HTTP_X_REQUESTED_WITH="XMLHttpRequest").data["code"], 1) @login_required @@ -324,7 +357,7 @@ class AdminRequiredDecoratorTest(TestCase): def test_fbv_without_args(self): # 没登陆 response = self.client.get("/admin_required_test/fbv/1/") - self.assertTemplateUsed(response, "utils/error.html") + self.assertRedirects(response, "/login/") # 登陆后 self.client.login(username="test", password="test") @@ -334,7 +367,7 @@ class AdminRequiredDecoratorTest(TestCase): def test_fbv_with_args(self): # 没登陆 response = self.client.get("/admin_required_test/fbv/1024/") - self.assertTemplateUsed(response, "utils/error.html") + self.assertRedirects(response, "/login/") # 登陆后 self.client.login(username="test", password="test") @@ -343,8 +376,8 @@ class AdminRequiredDecoratorTest(TestCase): def test_cbv_without_args(self): # 没登陆 - response = self.client.get("/admin_required_test/cbv/1/") - self.assertTemplateUsed(response, "utils/error.html") + response = self.client.get("/admin_required_test/cbv/1/", HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.data, {"code": 1, "data": u"请先登录"}) # 登陆后 self.client.login(username="test", password="test") @@ -354,7 +387,7 @@ class AdminRequiredDecoratorTest(TestCase): 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.assertEqual(response.data, {"code": 1, "data": u"请先登录"}) # 登陆后 self.client.login(username="test", password="test") @@ -362,16 +395,100 @@ class AdminRequiredDecoratorTest(TestCase): self.assertEqual(response.content, "1024") +@super_admin_required +def super_admin_required_FBV_test_without_args(request): + return HttpResponse("function based view test1") + + +@super_admin_required +def super_admin_required_FBC_test_with_args(request, problem_id): + return HttpResponse(problem_id) + + +class SuperAdminRequiredCBVTestWithoutArgs(APIView): + @super_admin_required + def get(self, request): + return HttpResponse("class based view login required test1") + + +class SuperAdminRequiredCBVTestWithArgs(APIView): + @super_admin_required + def get(self, request, problem_id): + return HttpResponse(problem_id) + + +class SuperAdminRequiredDecoratorTest(TestCase): + urls = 'account.test_urls' + + def setUp(self): + self.client = Client() + create_user(admin_type=SUPER_ADMIN) + + def test_fbv_without_args(self): + # 没登陆 + response = self.client.get("/super_admin_required_test/fbv/1/") + self.assertRedirects(response, "/login/") + + # 登陆后 + self.client.login(username="test", password="111111") + response = self.client.get("/super_admin_required_test/fbv/1/") + self.assertEqual(response.content, "function based view test1") + + def test_fbv_with_args(self): + # 没登陆 + response = self.client.get("/super_admin_required_test/fbv/1024/") + self.assertRedirects(response, "/login/") + + # 登陆后 + self.client.login(username="test", password="111111") + response = self.client.get("/super_admin_required_test/fbv/1024/") + self.assertEqual(response.content, "1024") + + def test_cbv_without_args(self): + # 没登陆 + response = self.client.get("/super_admin_required_test/cbv/1/", HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.data, {"code": 1, "data": u"请先登录"}) + + # 登陆后 + self.client.login(username="test", password="111111") + response = self.client.get("/super_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("/super_admin_required_test/cbv/1024/", HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.data, {"code": 1, "data": u"请先登录"}) + + # 登陆后 + self.client.login(username="test", password="111111") + response = self.client.get("/super_admin_required_test/cbv/10086/") + self.assertEqual(response.content, "10086") + + class UserLogoutTest(TestCase): def setUp(self): self.client = Client() - user = User.objects.create(username="test") - user.admin_type = 1 - user.set_password("1") - user.save() + create_user() def test_logout_success(self): self.client = Client() - self.client.login(username="test", password="1") + self.client.login(username="test", password="111111") response = self.client.get("/logout/") self.assertEqual(response.status_code, 302) + + +class IndexPageTest(TestCase): + def setUp(self): + create_user() + self.client = Client() + + def test_not_login_user(self): + self.assertTemplateUsed(self.client.get("/"), "oj/index.html") + + def test_no_referer_redirect(self): + self.client.login(username="test", password="111111") + self.assertRedirects(self.client.get("/"), "/problems/") + + def test_visit_with_referer(self): + self.client.login(username="test", password="111111") + self.assertTemplateUsed(self.client.get("/", HTTP_REFERER="/about/"), "oj/index.html")