l-29"> 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)

kodo - Gogs: Go Git Service

暂无描述

contactus.html 4.9KB

    <!doctype html> <html> <head> <meta charset="UTF-8"> <title>拍爱 PAI.AI 联系我们</title> <meta name="keywords" content="摄影 图片 影像 分享 交流 社交 交友 摄影师 女性 孩子 亲子 旅行 旅游 约拍 iphone android app" /> <link href="css/layout.css" rel="stylesheet" type="text/css" /> <script type="text/javascript" src="js/jquery.min.js"></script> <style> .my-map { margin: 0 auto 30px auto; width: 550px; height: 350px;float:left} .my-map .icon { background: url(http://lbs.amap.com/console/public/show/marker.png) no-repeat; } .my-map .icon-cir { height: 31px; width: 28px; } .my-map .icon-cir-red { background-position: -11px -5px; } </style> </head> <body> <div id="header"> <div class="content"> <a href="index.html" target="_self" class="logo"></a> <div class="navigation"> <a href="contactus.html" target="_self" class="current">联系我们</a> <a href="joinus.html" target="_self" >加入拍爱</a> <a href="aboutus.html" target="_self" >关于我们</a> <a href="index.html" target="_self" >首页</a> </div> </div> </div> <div id="container" ><div class="content contactus"> <div id="wrap" class="my-map map"> <div id="mapContainer"></div> </div> <script src="http://webapi.amap.com/maps?v=1.2&key=8325164e247e15eea68b59e89200988b"></script> <script> !function(){ var infoWindow, map, level = 16, center = {lng: 116.284361, lat: 39.931229}, features = [{type: "Marker", name: "拍爱 PAI.AI", desc: "北京市海淀区西八里庄路玲珑商务楼", color: "red", icon: "cir", offset: {x: -9, y: -31}, lnglat: {lng: 116.28449, lat: 39.930834}}]; function loadFeatures(){ for(var feature, data, i = 0, len = features.length, j, jl, path; i < len; i++){ data = features[i]; switch(data.type){ case "Marker": feature = new AMap.Marker({ map: map, position: new AMap.LngLat(data.lnglat.lng, data.lnglat.lat), zIndex: 3, extData: data, offset: new AMap.Pixel(data.offset.x, data.offset.y), title: data.name, content: '<div class="icon icon-' + data.icon + ' icon-'+ data.icon +'-' + data.color +'"></div>' }); break; case "Polyline": for(j = 0, jl = data.lnglat.length, path = []; j < jl; j++){ path.push(new AMap.LngLat(data.lnglat[j].lng, data.lnglat[j].lat)); } feature = new AMap.Polyline({ map: map, path: path, extData: data, zIndex: 2, strokeWeight: data.strokeWeight, strokeColor: data.strokeColor, strokeOpacity: data.strokeOpacity }); break; case "Polygon": for(j = 0, jl = data.lnglat.length, path = []; j < jl; j++){ path.push(new AMap.LngLat(data.lnglat[j].lng, data.lnglat[j].lat)); } feature = new AMap.Polygon({ map: map, path: path, extData: data, zIndex: 1, strokeWeight: data.strokeWeight, strokeColor: data.strokeColor, strokeOpacity: data.strokeOpacity, fillColor: data.fillColor, fillOpacity: data.fillOpacity }); break; default: feature = null; } if(feature){ AMap.event.addListener(feature, "click", mapFeatureClick); } } } function mapFeatureClick(e){ if(!infoWindow){ infoWindow = new AMap.InfoWindow({autoMove: true}); } var extData = e.target.getExtData(); infoWindow.setContent("<h5>" + extData.name + "</h5><div>" + extData.desc + "</div>"); infoWindow.open(map, e.lnglat); } map = new AMap.Map("mapContainer", {center: new AMap.LngLat(center.lng, center.lat), level: level}); loadFeatures(); map.plugin(["AMap.ToolBar", "AMap.OverView", "AMap.Scale"], function(){ map.addControl(new AMap.ToolBar); map.addControl(new AMap.OverView({isOpen: true})); map.addControl(new AMap.Scale); }); }(); </script> <p style="width:400px;float:right"><img src="img/weixin_qr.png" ><br><strong>关注拍爱 官方微信:</strong>pai_ai</p> <p style="width:400px;float:right"> <strong>商务合作:</strong>partner@pai.ai<br> <strong>用户反馈及帮助:</strong>feedback@pai.ai<br> <strong>公司地址:</strong>北京市海淀区西八里庄路玲珑商务楼 </p> </div></div> <div id="footer"> <div class="content foot"> <a href="aboutus.html" target="_self" >关于我们</a> <span>|</span> <a href="contactus.html" target="_self" >联系我们</a> ©2016 拍爱 PAI.AI 琼ICP备16000076号 </div> </div> </body> </html>