add api of lesman login & update other api

Brightcells 9 年 前
コミット
434468279f

+ 12 - 0
account/admin.py

@@ -1,14 +1,26 @@
1 1
 # -*- coding: utf-8 -*-
2 2
 
3 3
 from django.contrib import admin
4
+from django.contrib.auth.hashers import make_password
4 5
 
5 6
 from account.models import LensmanInfo
6 7
 
8
+from utils.uuid_utils import curtailUUID
9
+
7 10
 
8 11
 class LensmanInfoAdmin(admin.ModelAdmin):
12
+    readonly_fields = ('lensman_id', 'encryption', )
9 13
     list_display = ('lensman_id', 'name', 'sex', 'phone', 'location', 'proportion', 'status', 'created_at', 'updated_at')
10 14
     search_fields = ('name', 'phone', 'location')
11 15
     list_filter = ('sex', 'status')
12 16
 
17
+    def save_model(self, request, obj, form, change):
18
+        if not obj.lensman_id:
19
+            obj.lensman_id = curtailUUID(LensmanInfo, 'lensman_id')
20
+        if obj.password:
21
+            obj.encryption = make_password(obj.password, None, 'pbkdf2_sha256')
22
+            obj.password = None
23
+        obj.save()
24
+
13 25
 
14 26
 admin.site.register(LensmanInfo, LensmanInfoAdmin)

+ 29 - 0
account/migrations/0002_auto_20151202_2251.py

@@ -0,0 +1,29 @@
1
+# -*- coding: utf-8 -*-
2
+from __future__ import unicode_literals
3
+
4
+from django.db import models, migrations
5
+
6
+
7
+class Migration(migrations.Migration):
8
+
9
+    dependencies = [
10
+        ('account', '0001_initial'),
11
+    ]
12
+
13
+    operations = [
14
+        migrations.AddField(
15
+            model_name='lensmaninfo',
16
+            name='encryption',
17
+            field=models.CharField(help_text='\u6444\u5f71\u5e08\u5bc6\u7801', max_length=255, null=True, verbose_name='encryption', blank=True),
18
+        ),
19
+        migrations.AddField(
20
+            model_name='lensmaninfo',
21
+            name='password',
22
+            field=models.CharField(help_text='\u6444\u5f71\u5e08\u5bc6\u7801', max_length=255, null=True, verbose_name='password', blank=True),
23
+        ),
24
+        migrations.AddField(
25
+            model_name='lensmaninfo',
26
+            name='username',
27
+            field=models.CharField(null=True, max_length=255, blank=True, help_text='\u6444\u5f71\u5e08\u7528\u6237\u540d', unique=True, verbose_name='username', db_index=True),
28
+        ),
29
+    ]

+ 19 - 0
account/migrations/0003_auto_20151202_2313.py

@@ -0,0 +1,19 @@
1
+# -*- coding: utf-8 -*-
2
+from __future__ import unicode_literals
3
+
4
+from django.db import models, migrations
5
+
6
+
7
+class Migration(migrations.Migration):
8
+
9
+    dependencies = [
10
+        ('account', '0002_auto_20151202_2251'),
11
+    ]
12
+
13
+    operations = [
14
+        migrations.AlterField(
15
+            model_name='lensmaninfo',
16
+            name='lensman_id',
17
+            field=models.CharField(help_text='\u6444\u5f71\u5e08\u552f\u4e00\u6807\u8bc6', unique=True, max_length=255, verbose_name='lensman_id', db_index=True),
18
+        ),
19
+    ]

+ 6 - 3
account/models.py

@@ -5,8 +5,6 @@ from django.utils.translation import ugettext_lazy as _
5 5
 
6 6
 from pai2.basemodels import CreateUpdateMixin
7 7
 
8
-from shortuuidfield import ShortUUIDField
9
-
10 8
 
11 9
 class LensmanInfo(CreateUpdateMixin):
12 10
     MALE = 0
@@ -17,7 +15,12 @@ class LensmanInfo(CreateUpdateMixin):
17 15
         (FEMALE, u'女'),
18 16
     )
19 17
 
20
-    lensman_id = ShortUUIDField(_(u'lensman_id'), max_length=255, help_text=u'摄影师唯一标识', db_index=True)
18
+    lensman_id = models.CharField(_(u'lensman_id'), max_length=255, blank=True, null=True, help_text=u'摄影师唯一标识', db_index=True, unique=True)
19
+
20
+    username = models.CharField(_(u'username'), max_length=255, blank=True, null=True, help_text=u'摄影师用户名', db_index=True, unique=True)
21
+    password = models.CharField(_(u'password'), max_length=255, blank=True, null=True, help_text=u'摄影师密码')
22
+    encryption = models.CharField(_(u'encryption'), max_length=255, blank=True, null=True, help_text=u'摄影师密码')
23
+
21 24
     name = models.CharField(_(u'name'), max_length=255, blank=True, null=True, help_text=u'摄影师姓名')
22 25
     sex = models.IntegerField(_(u'sex'), choices=SEX_TYPE, default=MALE, help_text=u'摄影师性别')
23 26
     phone = models.CharField(_(u'phone'), max_length=255, blank=True, null=True, help_text=u'摄影师电话', db_index=True, unique=True)

+ 31 - 0
account/views.py

@@ -1,12 +1,43 @@
1 1
 # -*- coding: utf-8 -*-
2 2
 
3
+from django.contrib.auth.hashers import check_password
3 4
 from django.contrib.auth.models import User, Group
5
+from django.http import JsonResponse
6
+
4 7
 from rest_framework import viewsets
5 8
 
6 9
 from account.models import LensmanInfo
7 10
 from account.serializers import UserSerializer, GroupSerializer, LensmanInfoSerializer
8 11
 
9 12
 
13
+# curl -X POST -F username=xxxxxxx -F password=xxxxxxx http://api.xfoto.com.cn/login
14
+def user_login(request):
15
+    username = request.POST.get('username', '')
16
+    password = request.POST.get('password', '')
17
+
18
+    try:
19
+        lensman = LensmanInfo.objects.get(username=username)
20
+    except LensmanInfo.DoesNotExist:
21
+        return JsonResponse({
22
+            'status': 4000,
23
+            'message': u'用户不存在',
24
+        })
25
+
26
+    if not check_password(password, lensman.encryption):
27
+        return JsonResponse({
28
+            'status': 4001,
29
+            'message': u'用户密码错误',
30
+        })
31
+
32
+    return JsonResponse({
33
+        'status': 200,
34
+        'message': u'登录成功',
35
+        'data': {
36
+            'user': lensman.lensman_id
37
+        },
38
+    })
39
+
40
+
10 41
 class UserViewSet(viewsets.ModelViewSet):
11 42
     """
12 43
     API endpoint that allows users to be viewed or edited.

+ 5 - 0
api/urls.py

@@ -2,10 +2,15 @@
2 2
 
3 3
 from django.conf.urls import url
4 4
 
5
+from account import views as account_views
5 6
 from photo import views as photo_views
6 7
 
7 8
 
8 9
 urlpatterns = [
10
+    url(r'^login$', account_views.user_login, name='user_login'),
11
+]
12
+
13
+urlpatterns += [
9 14
     url(r'^uuid_init$', photo_views.uuid_init, name='uuid_init'),
10 15
     url(r'^uuid$', photo_views.uuid, name='uuid'),
11 16
     url(r'^photos/upload$', photo_views.upload_photo, name='upload_photo'),

+ 8 - 4
docs/errorcode

@@ -1,4 +1,8 @@
1
-1、照片上传 —— 401
2
-     4010 —— 参数错误
3
-     4011 —— 摄影师不存在
4
-     4012 —— 照片已存在
1
+1、用户信息 —— 400
2
+    4000 —— 用户不存在
3
+    4001 —— 用户密码错误
4
+
5
+2、照片上传 —— 401
6
+    4010 —— 参数错误
7
+    4011 —— 摄影师不存在
8
+    4012 —— 照片已存在

+ 12 - 0
pai2/settings.py

@@ -46,6 +46,8 @@ INSTALLED_APPS = (
46 46
     'photo',
47 47
 )
48 48
 
49
+INSTALLED_APPS += ('multidomain', )
50
+
49 51
 MIDDLEWARE_CLASSES = (
50 52
     'django.contrib.sessions.middleware.SessionMiddleware',
51 53
     'django.middleware.common.CommonMiddleware',
@@ -57,6 +59,13 @@ MIDDLEWARE_CLASSES = (
57 59
     'django.middleware.security.SecurityMiddleware',
58 60
 )
59 61
 
62
+MIDDLEWARE_CLASSES += ('multidomain.middleware.DomainMiddleware', )
63
+
64
+URL_CONFIG = (
65
+    # (r'^(.+\.)?xfoto\.com\.cn', 'pai2.urls_www'),
66
+    (r'^(.+\.)?api\.xfoto\.com\.cn', 'pai2.urls_api'),
67
+)
68
+
60 69
 ROOT_URLCONF = 'pai2.urls'
61 70
 
62 71
 TEMPLATES = [
@@ -138,6 +147,9 @@ REST_FRAMEWORK = {
138 147
     'PAGE_SIZE': 1
139 148
 }
140 149
 
150
+# 唯一标识设置
151
+CURTAIL_UUID_LENGTH = 7
152
+
141 153
 # 域名设置
142 154
 DOMAIN = 'http://xfoto.com.cn'
143 155
 

+ 7 - 3
pai2/urls.py

@@ -33,14 +33,18 @@ urlpatterns = [
33 33
 ]
34 34
 
35 35
 urlpatterns += [
36
-    url(r'^api/', include('api.urls', namespace='api')),
37
-    # url(r'^photo/', include('photo.urls', namespace='photo'))
36
+    # url(r'^api/', include('api.urls', namespace='api')),
37
+    url(r'^s/(?P<session>\w+)$', photo_views.session_detail, name='session_detail'),
38
+    url(r'^p/(?P<photo>\w+)$', photo_views.photo_standard, name='photo_standard'),  # standard thumbnail, available for free
39
+    url(r'^m/(?P<photo>\w+)$', photo_views.photo_medium, name='photo_medium'),  # medium/mobile version, without watermark, login or paid by others
40
+    url(r'^l/(?P<photo>\w+)$', photo_views.photo_large, name='photo_large'),  # large, might support server side panning later, login required
41
+    url(r'^r/(?P<photo>\w+)$', photo_views.photo_raw, name='photo_raw'),  # raw image, only for finishers
38 42
 ]
39 43
 
40 44
 # Wire up our API using automatic URL routing.
41 45
 # Additionally, we include login URLs for the browsable API.
42 46
 urlpatterns += [
43
-    url(r'^apihome/', include(router.urls)),
47
+    url(r'^api/', include(router.urls)),
44 48
     url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
45 49
 ]
46 50
 

+ 10 - 0
pai2/urls_api.py

@@ -0,0 +1,10 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+
4
+from django.conf import settings
5
+from django.conf.urls import include, url
6
+
7
+
8
+urlpatterns = [
9
+    url(r'^', include('api.urls', namespace='api')),
10
+]

+ 0 - 4
pai2/uwsgi.bak/pai2_nginx.conf

@@ -26,10 +26,6 @@ server {
26 26
         alias /home/paiai/work/pai2/collect_static; # your Django project's static files - amend as required
27 27
     }
28 28
 
29
-    location /p/  {
30
-        alias /home/paiai/work/pai2/media/photo;  # Photo
31
-    }
32
-
33 29
     # Finally, send all non-media requests to the Django server.
34 30
     location / {
35 31
         # uwsgi_pass  pai2;

+ 6 - 6
photo/models.py

@@ -47,16 +47,16 @@ class PhotosInfo(CreateUpdateMixin):
47 47
 
48 48
     @property
49 49
     def photo_url(self):
50
-        # return u'{0}/media/{1}'.format(settings.DOMAIN, self.photo_path) if self.photo_path else ''
51
-        return u'{0}/p/{1}'.format(settings.DOMAIN, self.photo_name) if self.photo_name else ''
50
+        return u'{0}/media/{1}'.format(settings.DOMAIN, self.photo_path) if self.photo_path else ''
51
+        # return u'{0}/p/{1}'.format(settings.DOMAIN, self.photo_name) if self.photo_name else ''
52 52
 
53 53
     def _data(self):
54 54
         return {
55 55
             'pk': self.pk,
56
-            'lensman_id': self.lensman_id,
57
-            'session_id': self.session_id,
58
-            'photo_id': self.photo_id,
59
-            'photo_url': self.photo_url,
56
+            'user': self.lensman_id,
57
+            'session': self.session_id,
58
+            'photo': self.photo_id,
59
+            # 'photo_url': self.photo_url,
60 60
         }
61 61
 
62 62
     data = property(_data)

+ 10 - 0
photo/templates/photo/photo_detail.html

@@ -0,0 +1,10 @@
1
+<!DOCTYPE html>
2
+<html>
3
+<head lang="en">
4
+    <meta charset="UTF-8">
5
+    <title></title>
6
+</head>
7
+<body>
8
+    <img src="{{ photo_url }}">
9
+</body>
10
+</html>

+ 12 - 0
photo/templates/photo/session_detail.html

@@ -0,0 +1,12 @@
1
+<!DOCTYPE html>
2
+<html>
3
+<head lang="en">
4
+    <meta charset="UTF-8">
5
+    <title></title>
6
+</head>
7
+<body>
8
+    {% for photo in photos %}
9
+    <div><img src="{{ photo.photo_url }}"></div>
10
+    {% endfor %}
11
+</body>
12
+</html>

+ 33 - 7
photo/views.py

@@ -3,6 +3,7 @@
3 3
 from django.core.files.storage import default_storage
4 4
 from django.db import transaction
5 5
 from django.http import JsonResponse
6
+from django.shortcuts import render, redirect
6 7
 
7 8
 from rest_framework import viewsets
8 9
 
@@ -19,7 +20,7 @@ def uuid_init(request):
19 20
     num = int(request.GET.get('num', 1000))
20 21
 
21 22
     for i in xrange(num):
22
-        UUIDInfo.objects.create(uuid=curtailUUID())
23
+        UUIDInfo.objects.create(uuid=curtailUUID(UUIDInfo))
23 24
 
24 25
     return JsonResponse({
25 26
         'status': 200,
@@ -28,10 +29,10 @@ def uuid_init(request):
28 29
     })
29 30
 
30 31
 
31
-# curl -X POST -F lensman_id=123 -F num=100 http://xfoto.com.cn/api/uuid
32
+# curl -X POST -F user=xxxxxxx -F num=100 http://api.xfoto.com.cn/uuid
32 33
 @transaction.atomic
33 34
 def uuid(request):
34
-    lensman_id = request.POST.get('lensman_id', '')
35
+    lensman_id = request.POST.get('user', '')
35 36
     num = int(request.POST.get('num', 100))
36 37
 
37 38
     uuids = UUIDInfo.objects.select_for_update().filter(status=True)[:num]
@@ -58,10 +59,10 @@ def uuid(request):
58 59
 #               name with the symbol <. The difference between @ and < is then that @ makes a file get attached in the post as a file  upload,
59 60
 #               while the < makes a text field and just get the contents for that text field from a file.
60 61
 #
61
-# curl -X POST -F lensman_id=123 -F session_id=456 -F photo=@7056288a9ddf2db294cf50a943920989.jpg;filename=789 http://xfoto.com.cn/api/photos/upload
62
+# curl -X POST -F user=xxxxxxx -F session=xxxxxxx -F photo=@xxxxxxx.jpg http://api.xfoto.com.cn/photos/upload
62 63
 def upload_photo(request):
63
-    lensman_id = request.POST.get('lensman_id', '')
64
-    session_id = request.POST.get('session_id', '')
64
+    lensman_id = request.POST.get('user', '')
65
+    session_id = request.POST.get('session', '')
65 66
 
66 67
     photo = request.FILES.get('photo', '')
67 68
 
@@ -79,7 +80,7 @@ def upload_photo(request):
79 80
             'message': u'摄影师不存在',
80 81
         })
81 82
 
82
-    photo_id = curtailUUID()
83
+    photo_id = curtailUUID(PhotosInfo, 'photo_id')
83 84
 
84 85
     _, extension = os.path.splitext(photo.name)
85 86
     # photo_path = 'photo/{0}/{1}/{2}{3}'.format(lensman_id, session_id, photo_id, extension)
@@ -105,6 +106,31 @@ def upload_photo(request):
105 106
     })
106 107
 
107 108
 
109
+def session_detail(request, session):
110
+    photos = PhotosInfo.objects.filter(session_id=session)
111
+    return render(request, 'photo/session_detail.html', {'photos': photos})
112
+
113
+
114
+def photo_standard(request, photo):
115
+    photo = PhotosInfo.objects.get(photo_id=photo)
116
+    return render(request, 'photo/photo_detail.html', {'photo_url': photo.photo_url})
117
+
118
+
119
+def photo_medium(request, photo):
120
+    photo = PhotosInfo.objects.get(photo_id=photo)
121
+    return render(request, 'photo/photo_detail.html', {'photo_url': photo.photo_url})
122
+
123
+
124
+def photo_large(request, photo):
125
+    photo = PhotosInfo.objects.get(photo_id=photo)
126
+    return render(request, 'photo/photo_detail.html', {'photo_url': photo.photo_url})
127
+
128
+
129
+def photo_raw(request, photo):
130
+    photo = PhotosInfo.objects.get(photo_id=photo)
131
+    return render(request, 'photo/photo_detail.html', {'photo_url': photo.photo_url})
132
+
133
+
108 134
 class PhotoInfoViewSet(viewsets.ModelViewSet):
109 135
     queryset = PhotosInfo.objects.all().order_by('-created_at')
110 136
     serializer_class = PhotosInfoSerializer

+ 5 - 3
utils/uuid_utils.py

@@ -1,16 +1,18 @@
1 1
 # -*- coding: utf-8 -*-
2 2
 
3
+from django.conf import settings
4
+
3 5
 from photo.models import UUIDInfo
4 6
 
5 7
 import shortuuid
6 8
 
7 9
 
8
-def curtailUUID(length=10):
10
+def curtailUUID(model, field='uuid', length=settings.CURTAIL_UUID_LENGTH):
9 11
     flag = True
10 12
     while flag:
11 13
         uuid = shortuuid.uuid()[-length:]
12 14
         try:
13
-            UUIDInfo.objects.get(uuid=uuid)
14
-        except UUIDInfo.DoesNotExist:
15
+            model.objects.get(**{field: uuid})
16
+        except model.DoesNotExist:
15 17
             flag = False
16 18
     return uuid