diff --git a/account/migrations/0001_initial.py b/account/migrations/0001_initial.py new file mode 100644 index 00000000..4f552993 --- /dev/null +++ b/account/migrations/0001_initial.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='User', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('password', models.CharField(max_length=128, verbose_name='password')), + ('last_login', models.DateTimeField(null=True, verbose_name='last login', blank=True)), + ('username', models.CharField(unique=True, max_length=30)), + ], + options={ + 'db_table': 'user', + }, + ), + migrations.CreateModel( + name='AdminGroup', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ], + ), + migrations.AddField( + model_name='user', + name='admin_group', + field=models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, to='account.AdminGroup', null=True), + ), + ] diff --git a/account/models.py b/account/models.py index 3b4bef7a..cb4ec922 100644 --- a/account/models.py +++ b/account/models.py @@ -7,9 +7,21 @@ class AdminGroup(models.Model): pass +class UserManager(models.Manager): + use_in_migrations = True + + def get_by_natural_key(self, username): + return self.get(**{self.model.USERNAME_FIELD: username}) + + class User(AbstractBaseUser): username = models.CharField(max_length=30, unique=True) admin_group = models.ForeignKey(AdminGroup, null=True, on_delete=models.SET_NULL) + USERNAME_FIELD = 'username' + REQUIRED_FIELDS = [] + + objects = UserManager() + class Meta: db_table = "user" diff --git a/account/serializers.py b/account/serializers.py new file mode 100644 index 00000000..ffa6b3b1 --- /dev/null +++ b/account/serializers.py @@ -0,0 +1,7 @@ +# coding=utf-8 +from rest_framework import serializers + + +class UserLoginSerializer(serializers.Serializer): + username = serializers.CharField(max_length=30) + password = serializers.CharField(max_length=30) diff --git a/account/tests.py b/account/tests.py index 7ce503c2..25d2b12c 100644 --- a/account/tests.py +++ b/account/tests.py @@ -1,3 +1,38 @@ -from django.test import TestCase +# coding=utf-8 +from django.core.urlresolvers import reverse +from django.test import TestCase, Client -# Create your tests here. +from rest_framework.test import APITestCase, APIClient + +from .models import User + + +class UserLoginTest(TestCase): + def test_login_page(self): + client = Client() + response = client.get(reverse("user_login_page")) + self.assertTemplateUsed(response, "account/login.html") + + +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() + + def test_invalid_data(self): + data = {"username": "test"} + response = self.client.post(self.url, data=data) + self.assertEqual(response.data["code"], 1) + + def test_error_username_or_password(self): + error_data = {"username": "test", "password": "test11"} + 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"} + response = self.client.post(self.url, data=data) + self.assertEqual(response.data, {"code": 0, "data": u"登录成功"}) diff --git a/account/views.py b/account/views.py index a9ec5d8c..32b77c92 100644 --- a/account/views.py +++ b/account/views.py @@ -1 +1,38 @@ -from django.shortcuts import render \ No newline at end of file +# coding=utf-8 +from django.contrib import auth +from django.shortcuts import render +from rest_framework.views import APIView + +from utils.shortcuts import serializer_invalid_response, error_response, success_response + +from .models import User +from .serializers import UserLoginSerializer + + +class UserLoginAPIView(APIView): + def post(self, request): + """ + 用户登录json api接口 + --- + request_serializer: UserLoginSerializer + """ + serializer = UserLoginSerializer(data=request.DATA) + if serializer.is_valid(): + data = serializer.data + user = auth.authenticate(username=data["username"], password=data["password"]) + # 用户名或密码错误的话 返回None + if user: + auth.login(request, user) + return success_response(u"登录成功") + else: + return error_response(u"用户名或密码错误") + else: + return serializer_invalid_response(serializer) + + +class UserRegisterView(APIView): + def get(self, request): + pass + + def post(self, request): + pass diff --git a/admin/tests.py b/admin/tests.py index 7ce503c2..e69de29b 100644 --- a/admin/tests.py +++ b/admin/tests.py @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/qduoj/settings.py b/qduoj/settings.py index cf9ab2d4..2f285519 100644 --- a/qduoj/settings.py +++ b/qduoj/settings.py @@ -46,6 +46,12 @@ INSTALLED_APPS = ( 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + + 'account', + + + 'rest_framework', + 'rest_framework_swagger', ) MIDDLEWARE_CLASSES = ( @@ -113,6 +119,12 @@ STATIC_URL = '/static/' STATICFILES_DIRS = (os.path.join(BASE_DIR, "static"),) +TEMPLATE_DIRS = ( + os.path.join(BASE_DIR, "template"), +) + +AUTH_USER_MODEL = 'account.User' + LOGGING = { 'version': 1, 'disable_existing_loggers': True, @@ -147,7 +159,7 @@ LOGGING = { }, 'django.db.backends': { 'handlers': ['console'], - 'level': 'DEBUG', + 'level': 'ERROR', 'propagate': True, } }, diff --git a/qduoj/urls.py b/qduoj/urls.py index 3f06f9a5..e1a8bfa9 100644 --- a/qduoj/urls.py +++ b/qduoj/urls.py @@ -3,10 +3,17 @@ from django.conf.urls import include, url from django.contrib import admin from django.views.generic import TemplateView +from account.views import UserLoginAPIView + urlpatterns = [ # Examples: # url(r'^$', 'qduoj.views.home', name='home'), # url(r'^blog/', include('blog.urls')), + url(r'^docs/', include('rest_framework_swagger.urls')), + url(r'^admin/', include(admin.site.urls)), + url(r'^login/$', TemplateView.as_view(template_name="account/login.html"), name="user_login_page"), + url(r'^api/login/$', UserLoginAPIView.as_view(), name="user_login_api"), + ] diff --git a/requirements.txt b/requirements.txt index 21a0a191..dfd96bcd 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,4 +3,5 @@ MySQL-python redis django-redis-sessions djangorestframework +django-rest-swagger celery diff --git a/template/account/login.html b/template/account/login.html new file mode 100644 index 00000000..71ce6922 --- /dev/null +++ b/template/account/login.html @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/utils/shortcuts.py b/utils/shortcuts.py index 9bad5790..bd5f2868 100644 --- a/utils/shortcuts.py +++ b/utils/shortcuts.py @@ -1 +1,14 @@ # coding=utf-8 +from rest_framework.response import Response + + +def error_response(error_reason): + return Response(data={"code": 1, "data": error_reason}) + + +def serializer_invalid_response(serializer): + return error_response(serializer.errors) + + +def success_response(data): + return Response(data={"code": 0, "data": data}) \ No newline at end of file