2
+    SEX_TYPE = (
83
+        (MALE, u'男'),
84
+        (FEMALE, u'女'),
85
+    )
86
+
87
+    user_id = models.CharField(_(u'user_id'), max_length=255, blank=True, null=True, help_text=u'用户唯一标识', db_index=True, unique=True)
88
+
89
+    username = models.CharField(_(u'username'), max_length=255, blank=True, null=True, help_text=u'用户用户名', db_index=True, unique=True)
90
+    password = models.CharField(_(u'password'), max_length=255, blank=True, null=True, help_text=u'用户密码')
91
+
92
+    name = models.CharField(_(u'name'), max_length=255, blank=True, null=True, help_text=u'用户姓名')
93
+    sex = models.IntegerField(_(u'sex'), choices=SEX_TYPE, default=MALE, help_text=u'用户性别')
94
+    phone = models.CharField(_(u'phone'), max_length=255, blank=True, null=True, help_text=u'用户电话', db_index=True, unique=True)
95
+    location = models.CharField(_(u'location'), max_length=255, blank=True, null=True, help_text=u'用户地址')
96
+
97
+    user_status = models.IntegerField(_(u'user_status'), choices=USER_STATUS, default=UNVERIFIED)
98
+
99
+    signup_ip = models.CharField(_(u'signup_ip'), max_length=255, blank=True, null=True, help_text=_(u'注册IP'))
100
+    login_ip = models.CharField(_(u'login_ip'), max_length=255, blank=True, null=True, help_text=_(u'登录IP'))
101
+    login_at = models.DateTimeField(_(u'login_at'), blank=True, null=True, help_text=_(u'登录时间'))
102
+
103
+    class Meta:
104
+        verbose_name = _(u'userinfo')
105
+        verbose_name_plural = _(u'userinfo')
106
+
107
+    def __unicode__(self):
108
+        return unicode(self.pk)
109
+
110
+    def _data(self):
111
+        return {
112
+            'user_id': self.user_id,
113
+            'username': self.username,
114
+        }
115
+
116
+    data = property(_data)
117
+
118
+
119
+class UserLoginLogInfo(CreateUpdateMixin):
120
+    SUCCESS = 0
121
+    PWD_ERROR = 1
122
+    OTHER = 2
123
+
124
+    LOGIN_RESULT = (
125
+        (SUCCESS, u'登录成功'),
126
+        (PWD_ERROR, u'密码错误'),
127
+        (OTHER, u'其他'),
128
+    )
129
+
130
+    user_id = models.CharField(_(u'user_id'), max_length=255, blank=True, null=True, help_text=u'用户唯一标识', db_index=True)
131
+    login_ip = models.CharField(_(u'login_ip'), max_length=255, blank=True, null=True, help_text=_(u'登录IP'))
132
+    login_result = models.IntegerField(_(u'login_result'), choices=LOGIN_RESULT, default=SUCCESS)
133
+
134
+    class Meta:
135
+        verbose_name = _(u'userloginloginfo')
136
+        verbose_name_plural = _(u'userloginloginfo')
137
+
138
+    def __unicode__(self):
139
+        return unicode(self.pk)

+ 7 - 1
account/serializers.py

@@ -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')

+ 92 - 4
account/views.py

@@ -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

+ 8 - 5
api/urls.py

@@ -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
 ]

+ 6 - 2
docs/errorcode

@@ -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 —— 参数错误

+ 4 - 1
pai2/urls.py

@@ -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

+ 0 - 1
pai2/urls_api.py

@@ -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 - 1
requirements.txt

@@ -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

+ 5 - 0
utils/ip_utils.py

@@ -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']

+ 0 - 2
utils/uuid_utils.py

@@ -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
 

Sign In - Gogs: Go Git Service

Sign In