modify guest_login_api

Brightcells 9 年之前
父节点
当前提交
63eaee0951

+ 1 - 1
account/admin.py

@@ -33,7 +33,7 @@ class LensmanIncomeExpensesInfoAdmin(admin.ModelAdmin):
33 33
 
34 34
 class UserInfoAdmin(admin.ModelAdmin):
35 35
     readonly_fields = ('user_id', )
36
-    list_display = ('user_id', 'user_from', 'username', 'wx_uid', 'name', 'sex', 'phone', 'location', 'user_status', 'status', 'created_at', 'updated_at')
36
+    list_display = ('user_id', 'user_from', 'username', 'wx_uid', 'name', 'sex', 'nickname', 'phone', 'location', 'user_status', 'status', 'created_at', 'updated_at')
37 37
     search_fields = ('name', 'phone', 'location')
38 38
     list_filter = ('user_from', 'sex', 'user_status', 'status')
39 39
 

+ 19 - 0
account/migrations/0010_userinfo_uuid.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', '0009_auto_20160428_1410'),
11
+    ]
12
+
13
+    operations = [
14
+        migrations.AddField(
15
+            model_name='userinfo',
16
+            name='uuid',
17
+            field=models.CharField(max_length=255, blank=True, help_text='\u901a\u7528\u552f\u4e00\u8bc6\u522b\u7801 (Universally Unique Identifier)', null=True, verbose_name='uuid', db_index=True),
18
+        ),
19
+    ]

+ 1 - 0
account/models.py

@@ -127,6 +127,7 @@ class UserInfo(CreateUpdateMixin):
127 127
     user_id = models.CharField(_(u'user_id'), max_length=255, blank=True, null=True, help_text=u'用户唯一标识', db_index=True, unique=True)
128 128
 
129 129
     user_from = models.IntegerField(_(u'user_from'), choices=USER_FROM, default=APP_USER, help_text=u'用户来源')
130
+    uuid = models.CharField(_(u'uuid'), max_length=255, blank=True, null=True, help_text=u'通用唯一识别码 (Universally Unique Identifier)', db_index=True)
130 131
     # APP 创建用户
131 132
     username = models.CharField(_(u'username'), max_length=255, blank=True, null=True, help_text=u'用户用户名', db_index=True, unique=True)
132 133
     password = models.CharField(_(u'password'), max_length=255, blank=True, null=True, help_text=u'用户密码')

+ 38 - 5
account/views.py

@@ -1,7 +1,6 @@
1 1
 # -*- coding: utf-8 -*-
2 2
 
3 3
 from curtail_uuid import CurtailUUID
4
-from django.conf import settings
5 4
 from django.contrib.auth.hashers import check_password, make_password
6 5
 from django.contrib.auth.models import Group, User
7 6
 from django.http import JsonResponse
@@ -10,9 +9,12 @@ from TimeConvert import TimeConvert as tc
10 9
 
11 10
 from account.models import LensmanInfo, UserInfo, UserLoginLogInfo
12 11
 from account.serializers import GroupSerializer, LensmanInfoSerializer, UserInfoSerializer, UserSerializer
12
+from operation.models import GuestEntranceControlInfo
13 13
 from utils.error.errno_utils import LensmanStatusCode, UserStatusCode
14 14
 from utils.error.response_utils import response
15 15
 from utils.ip_utils import ip_addr
16
+from utils.redis.rversion import get_guest_entrance_control
17
+from utils.version_utils import is_version_match
16 18
 
17 19
 
18 20
 # curl -X POST -F username=xxxxxxx -F password=xxxxxxx http://api.pai.ai/login
@@ -209,10 +211,41 @@ def wx_authorize_api(request):
209 211
 
210 212
 
211 213
 def guest_login_api(request):
212
-    try:
213
-        user = UserInfo.objects.get(user_id=settings.GUEST_USER_ID)
214
-    except UserInfo.DoesNotExist:
215
-        return response(UserStatusCode.GUEST_NOT_FOUND)
214
+    """ 游客登录 """
215
+    gen = get_guest_entrance_control()
216
+
217
+    # 是否配置游客入口控制信息
218
+    if not gen:
219
+        return response(UserStatusCode.GUEST_NOT_ALLOWED)
220
+
221
+    # 平台校验
222
+    platform = gen.get('platform', '')
223
+    if request.Android:
224
+        if platform not in [GuestEntranceControlInfo.ADR, GuestEntranceControlInfo.BOTH]:
225
+            return response(UserStatusCode.GUEST_NOT_ALLOWED)
226
+    else:
227
+        if platform not in [GuestEntranceControlInfo.IOS, GuestEntranceControlInfo.BOTH]:
228
+            return response(UserStatusCode.GUEST_NOT_ALLOWED)
229
+
230
+    # 版本校验
231
+    if not is_version_match(request, gen):
232
+        return response(UserStatusCode.GUEST_NOT_ALLOWED)
233
+
234
+    # 通用唯一识别码 (Universally Unique Identifier)
235
+    uuid = request.POST.get('uuid', '')
236
+    # 游客字段
237
+    fields = {
238
+        'user_id': CurtailUUID.uuid(UserInfo, 'user_id'),
239
+        'user_from': UserInfo.GUEST_USER,
240
+        'uuid': uuid,
241
+        'nickname': u'游客',
242
+        'user_status': UserInfo.ACTIVATED,
243
+    }
244
+    # 若 uuid 存在,则 get_or_create,否则 create
245
+    if uuid:
246
+        user, created = UserInfo.objects.get_or_create(user_from=UserInfo.GUEST_USER, uuid=uuid, defaults=fields)
247
+    else:
248
+        user = UserInfo.objects.create(**fields)
216 249
 
217 250
     return JsonResponse({
218 251
         'status': 200,

+ 13 - 1
operation/admin.py

@@ -2,7 +2,8 @@
2 2
 
3 3
 from django.contrib import admin
4 4
 
5
-from operation.models import FeedbackInfo, LatestAppInfo, SplashInfo
5
+from operation.models import FeedbackInfo, GuestEntranceControlInfo, LatestAppInfo, SplashInfo
6
+from utils.redis.rversion import set_guest_entrance_control
6 7
 
7 8
 
8 9
 class LatestAppInfoAdmin(admin.ModelAdmin):
@@ -17,6 +18,17 @@ class FeedbackInfoAdmin(admin.ModelAdmin):
17 18
     list_display = ('user_id', 'feedback', 'status', 'created_at', 'updated_at')
18 19
 
19 20
 
21
+class GuestEntranceControlInfoAdmin(admin.ModelAdmin):
22
+    list_display = ('platform', 'min_adr', 'max_adr', 'min_ios', 'max_ios', 'status', 'created_at', 'updated_at')
23
+
24
+    def save_model(self, request, obj, form, change):
25
+        obj.save()
26
+
27
+        # 设置游客入口控制
28
+        set_guest_entrance_control(obj)
29
+
30
+
20 31
 admin.site.register(LatestAppInfo, LatestAppInfoAdmin)
21 32
 admin.site.register(SplashInfo, SplashInfoAdmin)
22 33
 admin.site.register(FeedbackInfo, FeedbackInfoAdmin)
34
+admin.site.register(GuestEntranceControlInfo, GuestEntranceControlInfoAdmin)

+ 32 - 0
operation/migrations/0004_guestentrancecontrolinfo.py

@@ -0,0 +1,32 @@
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
+        ('operation', '0003_feedbackinfo'),
11
+    ]
12
+
13
+    operations = [
14
+        migrations.CreateModel(
15
+            name='GuestEntranceControlInfo',
16
+            fields=[
17
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
18
+                ('status', models.BooleanField(default=True, help_text='\u72b6\u6001', db_index=True, verbose_name='status')),
19
+                ('created_at', models.DateTimeField(help_text='\u521b\u5efa\u65f6\u95f4', verbose_name='created_at', auto_now_add=True)),
20
+                ('updated_at', models.DateTimeField(help_text='\u66f4\u65b0\u65f6\u95f4', verbose_name='updated_at', auto_now=True)),
21
+                ('platform', models.IntegerField(default=0, help_text='\u652f\u6301\u5e73\u53f0', db_index=True, verbose_name='plat', choices=[(0, '\u5168\u5e73\u53f0'), (1, 'Android'), (2, 'iOS')])),
22
+                ('min_adr', models.CharField(help_text='Adr \u6700\u4f4e\u7248\u672c', max_length=255, null=True, verbose_name='min_adr', blank=True)),
23
+                ('min_ios', models.CharField(help_text='iOS \u6700\u4f4e\u7248\u672c', max_length=255, null=True, verbose_name='min_ios', blank=True)),
24
+                ('max_adr', models.CharField(help_text='Adr \u6700\u9ad8\u7248\u672c', max_length=255, null=True, verbose_name='max_adr', blank=True)),
25
+                ('max_ios', models.CharField(help_text='iOS \u6700\u9ad8\u7248\u672c', max_length=255, null=True, verbose_name='max_ios', blank=True)),
26
+            ],
27
+            options={
28
+                'verbose_name': 'guestentrancecontrolinfo',
29
+                'verbose_name_plural': 'guestentrancecontrolinfo',
30
+            },
31
+        ),
32
+    ]

+ 25 - 7
operation/models.py

@@ -8,7 +8,7 @@ from django.conf import settings
8 8
 from django.db import models
9 9
 from django.utils.translation import ugettext_lazy as _
10 10
 
11
-from pai2.basemodels import CreateUpdateMixin
11
+from pai2.basemodels import CreateUpdateMixin, PlatformMixin, VersionMixin
12 12
 
13 13
 
14 14
 def upload_path(instance, old_filename):
@@ -38,14 +38,13 @@ class LatestAppInfo(CreateUpdateMixin):
38 38
     def final_latest_url(self):
39 39
         return self.latest_url or u'{}{}'.format(settings.DOMAIN, self.latest_app and self.latest_app.url)
40 40
 
41
-    def _data(self):
41
+    @property
42
+    def data(self):
42 43
         return {
43 44
             'latest_version': self.latest_version,
44 45
             'latest_url': self.final_latest_url,
45 46
         }
46 47
 
47
-    data = property(_data)
48
-
49 48
 
50 49
 class SplashInfo(CreateUpdateMixin):
51 50
     splash_image = models.ImageField(_(u'splash_image'), upload_to=upload_path, blank=True, null=True, help_text=u'启动页面图片')
@@ -63,15 +62,14 @@ class SplashInfo(CreateUpdateMixin):
63 62
     def splash_image_url(self):
64 63
         return self.splash_image and (settings.DOMAIN + self.splash_image.url)
65 64
 
66
-    def _data(self):
65
+    @property
66
+    def data(self):
67 67
         return {
68 68
             'splash_image_url': self.splash_image_url,
69 69
             'spalash_image_airtime': self.spalash_image_airtime,
70 70
             'spalash_image_deadline': self.spalash_image_deadline,
71 71
         }
72 72
 
73
-    data = property(_data)
74
-
75 73
 
76 74
 class FeedbackInfo(CreateUpdateMixin):
77 75
     user_id = models.CharField(_(u'user_id'), max_length=255, blank=True, null=True, help_text=u'用户唯一标识')
@@ -83,3 +81,23 @@ class FeedbackInfo(CreateUpdateMixin):
83 81
 
84 82
     def __unicode__(self):
85 83
         return u'{0.pk}'.format(self)
84
+
85
+
86
+class GuestEntranceControlInfo(CreateUpdateMixin, PlatformMixin, VersionMixin):
87
+
88
+    class Meta:
89
+        verbose_name = _('guestentrancecontrolinfo')
90
+        verbose_name_plural = _('guestentrancecontrolinfo')
91
+
92
+    def __unicode__(self):
93
+        return u'{0.pk}'.format(self)
94
+
95
+    @property
96
+    def data(self):
97
+        return {
98
+            'platform': self.platform,
99
+            'min_adr': self.min_adr,
100
+            'min_ios': self.min_ios,
101
+            'max_adr': self.max_adr,
102
+            'max_ios': self.max_ios,
103
+        }

+ 37 - 0
pai2/basemodels.py

@@ -3,6 +3,8 @@
3 3
 from django.db import models
4 4
 from django.utils.translation import ugettext_lazy as _
5 5
 
6
+from utils.version_utils import is_version_match
7
+
6 8
 
7 9
 class CreateUpdateMixin(models.Model):
8 10
     status = models.BooleanField(_(u'status'), default=True, help_text=_(u'状态'), db_index=True)
@@ -11,3 +13,38 @@ class CreateUpdateMixin(models.Model):
11 13
 
12 14
     class Meta:
13 15
         abstract = True
16
+
17
+
18
+class PlatformMixin(models.Model):
19
+    BOTH = 0
20
+    ADR = 1
21
+    IOS = 2
22
+
23
+    SUPPORT_PLATFORM = (
24
+        (BOTH, u'全平台'),
25
+        (ADR, u'Android'),
26
+        (IOS, u'iOS'),
27
+    )
28
+
29
+    platform = models.IntegerField(_(u'plat'), choices=SUPPORT_PLATFORM, default=BOTH, help_text=u'支持平台', db_index=True)
30
+
31
+    class Meta:
32
+        abstract = True
33
+
34
+
35
+class VersionMixin(models.Model):
36
+    min_adr = models.CharField(_(u'min_adr'), max_length=255, blank=True, null=True, help_text=u'Adr 最低版本')
37
+    min_ios = models.CharField(_(u'min_ios'), max_length=255, blank=True, null=True, help_text=u'iOS 最低版本')
38
+    max_adr = models.CharField(_(u'max_adr'), max_length=255, blank=True, null=True, help_text=u'Adr 最高版本')
39
+    max_ios = models.CharField(_(u'max_ios'), max_length=255, blank=True, null=True, help_text=u'iOS 最高版本')
40
+
41
+    def version_match(self, request):
42
+        return is_version_match(request, {
43
+            'min_adr': self.min_adr,
44
+            'min_ios': self.min_ios,
45
+            'max_adr': self.max_adr,
46
+            'max_ios': self.max_ios,
47
+        })
48
+
49
+    class Meta:
50
+        abstract = True

+ 6 - 0
pai2/settings.py

@@ -64,6 +64,7 @@ MIDDLEWARE_CLASSES = (
64 64
     'django.contrib.messages.middleware.MessageMiddleware',
65 65
     'django.middleware.clickjacking.XFrameOptionsMiddleware',
66 66
     'django.middleware.security.SecurityMiddleware',
67
+    'detect.middleware.UserAgentDetectionMiddleware',
67 68
 )
68 69
 
69 70
 MIDDLEWARE_CLASSES += ('multidomain.middleware.DomainMiddleware', )
@@ -254,6 +255,11 @@ GROUP_PER_PAGE = 20  # 群组每页数量
254 255
 # 游客设置
255 256
 GUEST_USER_ID = 'guest'
256 257
 
258
+# 版本设置
259
+MIN_VERSION = '0.0.0'
260
+MAX_VERSION = '999.999.999'
261
+CURRENT_VERSION = '1.0.0'
262
+
257 263
 # 价格设置
258 264
 LENSMAN_PHOTO_HAGGLE_MAX_TIMES = 3  # 摄影师照片最大砍价次数
259 265
 

+ 5 - 3
requirements.txt

@@ -1,10 +1,11 @@
1 1
 CodeConvert==2.0.4
2 2
 Django==1.8.4
3 3
 MySQL-python==1.2.5
4
-TimeConvert==1.1.6
4
+TimeConvert==1.2.0
5 5
 cryptography==1.2.1
6 6
 django-curtail-uuid==1.0.0
7
-django-logit==1.0.0
7
+django-detect==1.0.3
8
+django-logit==1.0.2
8 9
 django-multidomain==1.1.4
9 10
 django-shortuuidfield==0.1.3
10 11
 djangorestframework==3.3.1
@@ -17,4 +18,5 @@ pytz==2015.7
17 18
 redis==2.10.5
18 19
 shortuuid==0.4.2
19 20
 uWSGI==2.0.11.1
20
-wechatpy==1.2.6
21
+versions==0.10.0
22
+wechatpy==1.2.8

+ 1 - 1
utils/error/errno_utils.py

@@ -26,7 +26,7 @@ class UserStatusCode(BaseStatusCode):
26 26
     USER_PASSWORD_ERROR = StatusCodeField(400102, u'User Password Error', description=u'用户密码错误')
27 27
     USERNAME_HAS_REGISTERED = StatusCodeField(400103, u'Username Has Registered', description=u'用户名已注册')
28 28
 
29
-    GUEST_NOT_FOUND = StatusCodeField(400111, u'Guest Not Found', description=u'游客不存在')
29
+    GUEST_NOT_ALLOWED = StatusCodeField(400111, u'Guest Not ALLOWED', description=u'游客登录不允许')
30 30
 
31 31
 
32 32
 class PhotoStatusCode(BaseStatusCode):

+ 3 - 0
utils/redis/rkeys.py

@@ -26,3 +26,6 @@ LENSMAN_PHOTO_ORDER_RECORD = 'lensman:photo:order:record:%s:%s'  # STRING,摄
26 26
 # 系统消息相关
27 27
 SYSTEM_MESSAGE_READ_INFO = 'system:message:read:info:%s'  # STRING,系统消息读取信息,user_id
28 28
 SYSTEM_MESSAGE_DELETED_INFO = 'system:message:deleted:info:%s'  # STRING,系统消息删除信息,user_id
29
+
30
+# 游客入口相关
31
+GUEST_ENTRANCE_CONTROL_INFO = 'guest:entrance:control:info'  # STRING,游客入口控制信息

+ 24 - 0
utils/redis/rversion.py

@@ -0,0 +1,24 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+import json
4
+
5
+from django.conf import settings
6
+
7
+from utils.redis.rkeys import GUEST_ENTRANCE_CONTROL_INFO
8
+
9
+
10
+r = settings.REDIS_CACHE
11
+
12
+
13
+# 游客入口控制相关
14
+
15
+
16
+def set_guest_entrance_control(gen):
17
+    """ 设置游客入口控制 """
18
+    r.set(GUEST_ENTRANCE_CONTROL_INFO, json.dumps(gen.data))
19
+    return gen.data
20
+
21
+
22
+def get_guest_entrance_control():
23
+    """ 获取游客入口控制 """
24
+    return json.loads(r.get(GUEST_ENTRANCE_CONTROL_INFO) or '{}')

+ 10 - 0
utils/version_utils.py

@@ -0,0 +1,10 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from django.conf import settings
4
+from versions import Version
5
+
6
+
7
+def is_version_match(request, vers={}):
8
+    minv, maxv = (vers.get('min_adr', ''), vers.get('max_adr', '')) if request.Android else (vers.get('min_ios', ''), vers.get('max_ios', ''))
9
+    return Version.parse(minv or settings.MIN_VERSION) <= Version.parse(
10
+        request.REQUEST.get('version', settings.CURRENT_VERSION)) <= Version.parse(maxv or settings.MAX_VERSION)