2
+ SEX_TYPE = (
+ (MALE, u'男'),
+ (FEMALE, u'女'),
+ )
+
+ user_id = models.CharField(_(u'user_id'), max_length=255, blank=True, null=True, help_text=u'用户唯一标识', db_index=True, unique=True)
+
+ username = models.CharField(_(u'username'), max_length=255, blank=True, null=True, help_text=u'用户用户名', db_index=True, unique=True)
+ password = models.CharField(_(u'password'), max_length=255, blank=True, null=True, help_text=u'用户密码')
+
+ name = models.CharField(_(u'name'), max_length=255, blank=True, null=True, help_text=u'用户姓名')
+ sex = models.IntegerField(_(u'sex'), choices=SEX_TYPE, default=MALE, help_text=u'用户性别')
+ phone = models.CharField(_(u'phone'), max_length=255, blank=True, null=True, help_text=u'用户电话', db_index=True, unique=True)
+ location = models.CharField(_(u'location'), max_length=255, blank=True, null=True, help_text=u'用户地址')
+
+ user_status = models.IntegerField(_(u'user_status'), choices=USER_STATUS, default=UNVERIFIED)
+
+ signup_ip = models.CharField(_(u'signup_ip'), max_length=255, blank=True, null=True, help_text=_(u'注册IP'))
+ login_ip = models.CharField(_(u'login_ip'), max_length=255, blank=True, null=True, help_text=_(u'登录IP'))
+ login_at = models.DateTimeField(_(u'login_at'), blank=True, null=True, help_text=_(u'登录时间'))
+
+ class Meta:
+ verbose_name = _(u'userinfo')
+ verbose_name_plural = _(u'userinfo')
+
+ def __unicode__(self):
+ return unicode(self.pk)
+
+ def _data(self):
+ return {
+ 'user_id': self.user_id,
+ 'username': self.username,
+ }
+
+ data = property(_data)
+
+
+class UserLoginLogInfo(CreateUpdateMixin):
+ SUCCESS = 0
+ PWD_ERROR = 1
+ OTHER = 2
+
+ LOGIN_RESULT = (
+ (SUCCESS, u'登录成功'),
+ (PWD_ERROR, u'密码错误'),
+ (OTHER, u'其他'),
+ )
+
+ user_id = models.CharField(_(u'user_id'), max_length=255, blank=True, null=True, help_text=u'用户唯一标识', db_index=True)
+ login_ip = models.CharField(_(u'login_ip'), max_length=255, blank=True, null=True, help_text=_(u'登录IP'))
+ login_result = models.IntegerField(_(u'login_result'), choices=LOGIN_RESULT, default=SUCCESS)
+
+ class Meta:
+ verbose_name = _(u'userloginloginfo')
+ verbose_name_plural = _(u'userloginloginfo')
+
+ def __unicode__(self):
+ return unicode(self.pk)
@@ -3,7 +3,7 @@ |
||
| 3 | 3 |
from django.contrib.auth.models import User, Group |
| 4 | 4 |
from rest_framework import serializers |
| 5 | 5 |
|
| 6 |
-from account.models import LensmanInfo |
|
| 6 |
+from account.models import LensmanInfo, UserInfo |
|
| 7 | 7 |
|
| 8 | 8 |
|
| 9 | 9 |
class UserSerializer(serializers.HyperlinkedModelSerializer): |
@@ -22,3 +22,9 @@ class LensmanInfoSerializer(serializers.HyperlinkedModelSerializer): |
||
| 22 | 22 |
class Meta: |
| 23 | 23 |
model = LensmanInfo |
| 24 | 24 |
fields = ('lensman_id', 'name', 'sex', 'phone', 'location', 'proportion', 'created_at')
|
| 25 |
+ |
|
| 26 |
+ |
|
| 27 |
+class UserInfoSerializer(serializers.HyperlinkedModelSerializer): |
|
| 28 |
+ class Meta: |
|
| 29 |
+ model = UserInfo |
|
| 30 |
+ fields = ('user_id', 'name', 'sex', 'phone', 'location', 'user_status', 'created_at')
|
@@ -1,17 +1,22 @@ |
||
| 1 | 1 |
# -*- coding: utf-8 -*- |
| 2 | 2 |
|
| 3 |
-from django.contrib.auth.hashers import check_password |
|
| 3 |
+from django.contrib.auth.hashers import make_password, check_password |
|
| 4 | 4 |
from django.contrib.auth.models import User, Group |
| 5 | 5 |
from django.http import JsonResponse |
| 6 | 6 |
|
| 7 | 7 |
from rest_framework import viewsets |
| 8 | 8 |
|
| 9 |
-from account.models import LensmanInfo |
|
| 10 |
-from account.serializers import UserSerializer, GroupSerializer, LensmanInfoSerializer |
|
| 9 |
+from account.models import LensmanInfo, UserInfo, UserLoginLogInfo |
|
| 10 |
+from account.serializers import UserSerializer, GroupSerializer, LensmanInfoSerializer, UserInfoSerializer |
|
| 11 |
+ |
|
| 12 |
+from utils.ip_utils import ip_addr |
|
| 13 |
+from utils.uuid_utils import curtailUUID |
|
| 14 |
+ |
|
| 15 |
+from TimeConvert import TimeConvert as tc |
|
| 11 | 16 |
|
| 12 | 17 |
|
| 13 | 18 |
# curl -X POST -F username=xxxxxxx -F password=xxxxxxx http://api.xfoto.com.cn/login |
| 14 |
-def user_login(request): |
|
| 19 |
+def lesman_login_api(request): |
|
| 15 | 20 |
username = request.POST.get('username', '')
|
| 16 | 21 |
password = request.POST.get('password', '')
|
| 17 | 22 |
|
@@ -38,6 +43,84 @@ def user_login(request): |
||
| 38 | 43 |
}) |
| 39 | 44 |
|
| 40 | 45 |
|
| 46 |
+def user_is_registered_api(request): |
|
| 47 |
+ username = request.POST.get('username', '')
|
|
| 48 |
+ return JsonResponse({
|
|
| 49 |
+ 'status': 200, |
|
| 50 |
+ 'message': '', |
|
| 51 |
+ 'data': {
|
|
| 52 |
+ 'registered': UserInfo.objects.filter(username=username).exists(), |
|
| 53 |
+ } |
|
| 54 |
+ }) |
|
| 55 |
+ |
|
| 56 |
+ |
|
| 57 |
+def user_signup_api(request): |
|
| 58 |
+ username = request.POST.get('username', '')
|
|
| 59 |
+ password = request.POST.get('password', '')
|
|
| 60 |
+ |
|
| 61 |
+ if UserInfo.objects.filter(username=username).exists(): |
|
| 62 |
+ return JsonResponse({
|
|
| 63 |
+ 'status': 4010, |
|
| 64 |
+ 'message': u'该用户名已注册', |
|
| 65 |
+ }) |
|
| 66 |
+ |
|
| 67 |
+ user = UserInfo.objects.create( |
|
| 68 |
+ user_id=curtailUUID(UserInfo, 'user_id'), |
|
| 69 |
+ username=username, |
|
| 70 |
+ password=make_password(password, None, 'pbkdf2_sha256'), |
|
| 71 |
+ user_status=UserInfo.ACTIVATED, |
|
| 72 |
+ signup_ip=ip_addr(request), |
|
| 73 |
+ ) |
|
| 74 |
+ |
|
| 75 |
+ return JsonResponse({
|
|
| 76 |
+ 'status': 200, |
|
| 77 |
+ 'message': u'注册成功', |
|
| 78 |
+ 'data': user.data, |
|
| 79 |
+ }) |
|
| 80 |
+ |
|
| 81 |
+ |
|
| 82 |
+def user_login_api(request): |
|
| 83 |
+ username = request.POST.get('username', '')
|
|
| 84 |
+ password = request.POST.get('password', '')
|
|
| 85 |
+ |
|
| 86 |
+ try: |
|
| 87 |
+ user = UserInfo.objects.get(username=username) |
|
| 88 |
+ except UserInfo.DoesNotExist: |
|
| 89 |
+ return JsonResponse({
|
|
| 90 |
+ 'status': 4011, |
|
| 91 |
+ 'message': u'用户不存在', |
|
| 92 |
+ }) |
|
| 93 |
+ |
|
| 94 |
+ login_ip, login_at = ip_addr(request), tc.utc_datetime() |
|
| 95 |
+ |
|
| 96 |
+ if not check_password(password, user.password): |
|
| 97 |
+ UserLoginLogInfo.objects.create( |
|
| 98 |
+ user_id=user.user_id, |
|
| 99 |
+ login_ip=login_ip, |
|
| 100 |
+ login_result=UserLoginLogInfo.PWD_ERROR |
|
| 101 |
+ ) |
|
| 102 |
+ return JsonResponse({
|
|
| 103 |
+ 'status': 4012, |
|
| 104 |
+ 'message': u'用户密码错误', |
|
| 105 |
+ }) |
|
| 106 |
+ |
|
| 107 |
+ UserLoginLogInfo.objects.create( |
|
| 108 |
+ user_id=user.user_id, |
|
| 109 |
+ login_ip=login_ip, |
|
| 110 |
+ login_result=UserLoginLogInfo.SUCCESS |
|
| 111 |
+ ) |
|
| 112 |
+ |
|
| 113 |
+ user.login_ip = login_ip |
|
| 114 |
+ user.login_at = login_at |
|
| 115 |
+ user.save() |
|
| 116 |
+ |
|
| 117 |
+ return JsonResponse({
|
|
| 118 |
+ 'status': 200, |
|
| 119 |
+ 'message': u'登录成功', |
|
| 120 |
+ 'data': user.data, |
|
| 121 |
+ }) |
|
| 122 |
+ |
|
| 123 |
+ |
|
| 41 | 124 |
class UserViewSet(viewsets.ModelViewSet): |
| 42 | 125 |
""" |
| 43 | 126 |
API endpoint that allows users to be viewed or edited. |
@@ -57,3 +140,8 @@ class GroupViewSet(viewsets.ModelViewSet): |
||
| 57 | 140 |
class LensmanInfoViewSet(viewsets.ModelViewSet): |
| 58 | 141 |
queryset = LensmanInfo.objects.all().order_by('-created_at')
|
| 59 | 142 |
serializer_class = LensmanInfoSerializer |
| 143 |
+ |
|
| 144 |
+ |
|
| 145 |
+class UserInfoViewSet(viewsets.ModelViewSet): |
|
| 146 |
+ queryset = UserInfo.objects.all().order_by('-created_at')
|
|
| 147 |
+ serializer_class = UserInfoSerializer |
@@ -7,16 +7,19 @@ from photo import views as photo_views |
||
| 7 | 7 |
|
| 8 | 8 |
|
| 9 | 9 |
urlpatterns = [ |
| 10 |
- url(r'^login$', account_views.user_login, name='user_login'), |
|
| 10 |
+ url(r'^login$', account_views.lesman_login_api, name='lesman_login_api'), |
|
| 11 |
+ url(r'^u/is_registered$', account_views.user_is_registered_api, name='user_is_registered_api'), # 用户是否已经注册 |
|
| 12 |
+ url(r'^u/signup$', account_views.user_signup_api, name='user_signup_api'), # 用户注册 |
|
| 13 |
+ url(r'^u/login$', account_views.user_login_api, name='user_login_api'), # 用户登录 |
|
| 11 | 14 |
] |
| 12 | 15 |
|
| 13 | 16 |
urlpatterns += [ |
| 14 |
- url(r'^uuid_init$', photo_views.uuid_init, name='uuid_init'), |
|
| 15 |
- url(r'^uuid$', photo_views.uuid, name='uuid'), |
|
| 16 |
- url(r'^photos/upload$', photo_views.upload_photo, name='upload_photo'), |
|
| 17 |
+ url(r'^uuid_init$', photo_views.uuid_init, name='uuid_init'), # 生成唯一标识 |
|
| 18 |
+ url(r'^uuid$', photo_views.uuid, name='uuid'), # 获取唯一标识 |
|
| 19 |
+ url(r'^photos/upload$', photo_views.upload_photo, name='upload_photo'), # 上传图片 |
|
| 17 | 20 |
] |
| 18 | 21 |
|
| 19 | 22 |
urlpatterns += [ |
| 20 |
- url(r'^s/(?P<session>\w+)$', photo_views.session_detail_api, name='session_detail_api'), |
|
| 23 |
+ url(r'^s/(?P<session>\w+)$', photo_views.session_detail_api, name='session_detail_api'), # Session 详情 |
|
| 21 | 24 |
url(r'^p/(?P<photo>\w+)$', photo_views.photo_standard_api, name='photo_standard_api'), # standard thumbnail, available for free |
| 22 | 25 |
] |
@@ -1,6 +1,10 @@ |
||
| 1 | 1 |
1、用户信息 —— 400 |
| 2 |
- 4000 —— 用户不存在 |
|
| 3 |
- 4001 —— 用户密码错误 |
|
| 2 |
+ 4000 —— 摄影师不存在 |
|
| 3 |
+ 4001 —— 摄影师密码错误 |
|
| 4 |
+ |
|
| 5 |
+ 4010 —— 用户名已注册 |
|
| 6 |
+ 4011 —— 用户名不存在 |
|
| 7 |
+ 4012 —— 用户密码错误 |
|
| 4 | 8 |
|
| 5 | 9 |
2、照片上传 —— 401 |
| 6 | 10 |
4010 —— 参数错误 |
@@ -1,3 +1,5 @@ |
||
| 1 |
+# -*- coding: utf-8 -*- |
|
| 2 |
+ |
|
| 1 | 3 |
"""pai2 URL Configuration |
| 2 | 4 |
|
| 3 | 5 |
The `urlpatterns` list routes URLs to views. For more information please see: |
@@ -26,6 +28,7 @@ router = routers.DefaultRouter() |
||
| 26 | 28 |
# router.register(r'users', account_views.UserViewSet) |
| 27 | 29 |
# router.register(r'groups', account_views.GroupViewSet) |
| 28 | 30 |
router.register(r'lensmans', account_views.LensmanInfoViewSet) |
| 31 |
+router.register(r'users', account_views.UserInfoViewSet) |
|
| 29 | 32 |
router.register(r'photos', photo_views.PhotoInfoViewSet) |
| 30 | 33 |
|
| 31 | 34 |
urlpatterns = [ |
@@ -34,7 +37,7 @@ urlpatterns = [ |
||
| 34 | 37 |
|
| 35 | 38 |
urlpatterns += [ |
| 36 | 39 |
# url(r'^api/', include('api.urls', namespace='api')),
|
| 37 |
- url(r'^s/(?P<session>\w+)$', photo_views.session_detail, name='session_detail'), |
|
| 40 |
+ url(r'^s/(?P<session>\w+)$', photo_views.session_detail, name='session_detail'), # Session 详情 |
|
| 38 | 41 |
url(r'^p/(?P<photo>\w+)$', photo_views.photo_standard, name='photo_standard'), # standard thumbnail, available for free |
| 39 | 42 |
url(r'^m/(?P<photo>\w+)$', photo_views.photo_medium, name='photo_medium'), # medium/mobile version, without watermark, login or paid by others |
| 40 | 43 |
url(r'^l/(?P<photo>\w+)$', photo_views.photo_large, name='photo_large'), # large, might support server side panning later, login required |
@@ -1,6 +1,5 @@ |
||
| 1 | 1 |
# -*- coding: utf-8 -*- |
| 2 | 2 |
|
| 3 |
- |
|
| 4 | 3 |
from django.conf import settings |
| 5 | 4 |
from django.conf.urls import include, url |
| 6 | 5 |
|
@@ -1,7 +1,7 @@ |
||
| 1 | 1 |
CodeConvert==2.0.3 |
| 2 | 2 |
Django==1.8.4 |
| 3 | 3 |
MySQL-python==1.2.5 |
| 4 |
-TimeConvert==1.0.7 |
|
| 4 |
+TimeConvert==1.1.3 |
|
| 5 | 5 |
django-multidomain==1.1.4 |
| 6 | 6 |
django-shortuuidfield==0.1.3 |
| 7 | 7 |
djangorestframework==3.3.1 |
@@ -0,0 +1,5 @@ |
||
| 1 |
+# -*- coding: utf-8 -*- |
|
| 2 |
+ |
|
| 3 |
+ |
|
| 4 |
+def ip_addr(request): |
|
| 5 |
+ return request.META['HTTP_X_FORWARDED_FOR'] if 'HTTP_X_FORWARDED_FOR' in request.META else request.META['REMOTE_ADDR'] |
@@ -2,8 +2,6 @@ |
||
| 2 | 2 |
|
| 3 | 3 |
from django.conf import settings |
| 4 | 4 |
|
| 5 |
-from photo.models import UUIDInfo |
|
| 6 |
- |
|
| 7 | 5 |
import shortuuid |
| 8 | 6 |
|
| 9 | 7 |
|