@@ -10,9 +10,9 @@ from account.models import (LensmanIncomeExpensesInfo, LensmanInfo, LensmanLogin  | 
            ||
| 10 | 10 | 
                 | 
            
| 11 | 11 | 
                class LensmanInfoAdmin(admin.ModelAdmin):  | 
            
| 12 | 12 | 
                     readonly_fields = ('lensman_id', 'encryption', )
               | 
            
| 13 | 
                -    list_display = ('lensman_id', 'username', 'name', 'sex', 'phone', 'location', 'proportion', 'status', 'created_at', 'updated_at')
               | 
            |
| 13 | 
                +    list_display = ('lensman_id', 'unionid', 'username', 'name', 'sex', 'phone', 'location', 'proportion', 'balance', 'user_status', 'status', 'created_at', 'updated_at')
               | 
            |
| 14 | 14 | 
                     search_fields = ('name', 'phone', 'location')
               | 
            
| 15 | 
                -    list_filter = ('sex', 'status')
               | 
            |
| 15 | 
                +    list_filter = ('sex', 'user_status', 'status')
               | 
            |
| 16 | 16 | 
                 | 
            
| 17 | 17 | 
                def save_model(self, request, obj, form, change):  | 
            
| 18 | 18 | 
                if not obj.lensman_id:  | 
            
                @@ -20,11 +20,12 @@ class LensmanInfoAdmin(admin.ModelAdmin):  | 
            ||
| 20 | 20 | 
                obj.lensman_id = user_id  | 
            
| 21 | 21 | 
                 | 
            
| 22 | 22 | 
                         fields = {
               | 
            
| 23 | 
                + 'unionid': obj.unionid,  | 
            |
| 23 | 24 | 
                'name': obj.name,  | 
            
| 24 | 25 | 
                'sex': obj.sex,  | 
            
| 25 | 26 | 
                'phone': obj.phone,  | 
            
| 26 | 27 | 
                'location': obj.location,  | 
            
| 27 | 
                - 'user_status': obj.status,  | 
            |
| 28 | 
                + 'user_status': obj.user_status,  | 
            |
| 28 | 29 | 
                }  | 
            
| 29 | 30 | 
                user, created = UserInfo.objects.get_or_create(user_id=obj.lensman_id, user_from=UserInfo.LENSMAN_USER, defaults=fields)  | 
            
| 30 | 31 | 
                if not created:  | 
            
                @@ -49,7 +50,7 @@ class LensmanIncomeExpensesInfoAdmin(admin.ModelAdmin):  | 
            ||
| 49 | 50 | 
                 | 
            
| 50 | 51 | 
                class UserInfoAdmin(admin.ModelAdmin):  | 
            
| 51 | 52 | 
                     readonly_fields = ('user_id', )
               | 
            
| 52 | 
                -    list_display = ('user_id', 'user_from', 'username', 'wx_uid', 'name', 'sex', 'nickname', 'phone', 'location', 'balance', 'user_status', 'status', 'created_at', 'updated_at')
               | 
            |
| 53 | 
                +    list_display = ('user_id', 'user_from', 'username', 'wx_uid', 'unionid', 'name', 'sex', 'nickname', 'phone', 'location', 'balance', 'user_status', 'status', 'created_at', 'updated_at')
               | 
            |
| 53 | 54 | 
                     search_fields = ('name', 'phone', 'location')
               | 
            
| 54 | 55 | 
                     list_filter = ('user_from', 'sex', 'user_status', 'status')
               | 
            
| 55 | 56 | 
                 | 
            
                @@ -0,0 +1,52 @@  | 
            ||
| 1 | 
                +# -*- coding: utf-8 -*-  | 
            |
| 2 | 
                +from __future__ import unicode_literals  | 
            |
| 3 | 
                +  | 
            |
| 4 | 
                +from django.db import models, migrations  | 
            |
| 5 | 
                +import jsonfield.fields  | 
            |
| 6 | 
                +  | 
            |
| 7 | 
                +  | 
            |
| 8 | 
                +class Migration(migrations.Migration):  | 
            |
| 9 | 
                +  | 
            |
| 10 | 
                + dependencies = [  | 
            |
| 11 | 
                +        ('account', '0012_auto_20160627_1419'),
               | 
            |
| 12 | 
                + ]  | 
            |
| 13 | 
                +  | 
            |
| 14 | 
                + operations = [  | 
            |
| 15 | 
                + migrations.CreateModel(  | 
            |
| 16 | 
                + name='WechatInfo',  | 
            |
| 17 | 
                + fields=[  | 
            |
| 18 | 
                +                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
               | 
            |
| 19 | 
                +                ('status', models.BooleanField(default=True, help_text='\u72b6\u6001', db_index=True, verbose_name='status')),
               | 
            |
| 20 | 
                +                ('created_at', models.DateTimeField(help_text='\u521b\u5efa\u65f6\u95f4', verbose_name='created_at', auto_now_add=True)),
               | 
            |
| 21 | 
                +                ('updated_at', models.DateTimeField(help_text='\u66f4\u65b0\u65f6\u95f4', verbose_name='updated_at', auto_now=True)),
               | 
            |
| 22 | 
                +                ('unionid', models.CharField(help_text='\u5fae\u4fe1 Union ID', max_length=255, null=True, verbose_name='unionid', blank=True)),
               | 
            |
| 23 | 
                +                ('openids', jsonfield.fields.JSONField(help_text='\u5fae\u4fe1 Open IDs', null=True, verbose_name='openids', blank=True)),
               | 
            |
| 24 | 
                +                ('sex', models.IntegerField(default=1, help_text='\u7528\u6237\u6027\u522b', verbose_name='sex', choices=[(1, '\u7537'), (0, '\u5973')])),
               | 
            |
| 25 | 
                +                ('nickname', models.CharField(help_text='\u7528\u6237\u6635\u79f0', max_length=255, null=True, verbose_name='nickname', blank=True)),
               | 
            |
| 26 | 
                +                ('headimgurl', models.CharField(help_text='\u7528\u6237\u5934\u50cf', max_length=255, null=True, verbose_name='headimgurl', blank=True)),
               | 
            |
| 27 | 
                +                ('country', models.CharField(help_text='\u7528\u6237\u56fd\u5bb6', max_length=255, null=True, verbose_name='country', blank=True)),
               | 
            |
| 28 | 
                +                ('province', models.CharField(help_text='\u7528\u6237\u7701\u4efd', max_length=255, null=True, verbose_name='province', blank=True)),
               | 
            |
| 29 | 
                +                ('city', models.CharField(help_text='\u7528\u6237\u57ce\u5e02', max_length=255, null=True, verbose_name='city', blank=True)),
               | 
            |
| 30 | 
                +                ('location', models.CharField(help_text='\u7528\u6237\u5730\u5740', max_length=255, null=True, verbose_name='location', blank=True)),
               | 
            |
| 31 | 
                + ],  | 
            |
| 32 | 
                +            options={
               | 
            |
| 33 | 
                + 'verbose_name': 'wechatinfo',  | 
            |
| 34 | 
                + 'verbose_name_plural': 'wechatinfo',  | 
            |
| 35 | 
                + },  | 
            |
| 36 | 
                + ),  | 
            |
| 37 | 
                + migrations.AddField(  | 
            |
| 38 | 
                + model_name='lensmaninfo',  | 
            |
| 39 | 
                + name='unionid',  | 
            |
| 40 | 
                + field=models.CharField(null=True, max_length=255, blank=True, help_text='\u5fae\u4fe1 Union ID', unique=True, verbose_name='unionid', db_index=True),  | 
            |
| 41 | 
                + ),  | 
            |
| 42 | 
                + migrations.AddField(  | 
            |
| 43 | 
                + model_name='lensmaninfo',  | 
            |
| 44 | 
                + name='user_status',  | 
            |
| 45 | 
                + field=models.IntegerField(default=0, verbose_name='user_status', choices=[(0, '\u672a\u9a8c\u8bc1'), (1, '\u5df2\u6fc0\u6d3b'), (2, '\u5df2\u7981\u7528'), (3, '\u5df2\u5220\u9664'), (10, '\u5df2\u5206\u914d')]),  | 
            |
| 46 | 
                + ),  | 
            |
| 47 | 
                + migrations.AlterField(  | 
            |
| 48 | 
                + model_name='userinfo',  | 
            |
| 49 | 
                + name='unionid',  | 
            |
| 50 | 
                + field=models.CharField(null=True, max_length=255, blank=True, help_text='\u5fae\u4fe1 Union ID', unique=True, verbose_name='unionid', db_index=True),  | 
            |
| 51 | 
                + ),  | 
            |
| 52 | 
                + ]  | 
            
                @@ -2,6 +2,7 @@  | 
            ||
| 2 | 2 | 
                 | 
            
| 3 | 3 | 
                from django.db import models  | 
            
| 4 | 4 | 
                from django.utils.translation import ugettext_lazy as _  | 
            
| 5 | 
                +from jsonfield import JSONField  | 
            |
| 5 | 6 | 
                 | 
            
| 6 | 7 | 
                from pai2.basemodels import CreateUpdateMixin  | 
            
| 7 | 8 | 
                 | 
            
                @@ -15,8 +16,24 @@ class LensmanInfo(CreateUpdateMixin):  | 
            ||
| 15 | 16 | 
                (FEMALE, u'女'),  | 
            
| 16 | 17 | 
                )  | 
            
| 17 | 18 | 
                 | 
            
| 19 | 
                + UNVERIFIED = 0  | 
            |
| 20 | 
                + ACTIVATED = 1  | 
            |
| 21 | 
                + DISABLED = 2  | 
            |
| 22 | 
                + DELETED = 3  | 
            |
| 23 | 
                + ASSIGN = 10  | 
            |
| 24 | 
                +  | 
            |
| 25 | 
                + USER_STATUS = (  | 
            |
| 26 | 
                + (UNVERIFIED, u'未验证'),  | 
            |
| 27 | 
                + (ACTIVATED, u'已激活'),  | 
            |
| 28 | 
                + (DISABLED, u'已禁用'),  | 
            |
| 29 | 
                + (DELETED, u'已删除'),  | 
            |
| 30 | 
                + (ASSIGN, u'已分配'),  | 
            |
| 31 | 
                + )  | 
            |
| 32 | 
                +  | 
            |
| 18 | 33 | 
                lensman_id = models.CharField(_(u'lensman_id'), max_length=255, blank=True, null=True, help_text=u'摄影师唯一标识', db_index=True, unique=True)  | 
            
| 19 | 34 | 
                 | 
            
| 35 | 
                + unionid = models.CharField(_(u'unionid'), max_length=255, blank=True, null=True, help_text=u'微信 Union ID', db_index=True, unique=True)  | 
            |
| 36 | 
                +  | 
            |
| 20 | 37 | 
                username = models.CharField(_(u'username'), max_length=255, blank=True, null=True, help_text=u'摄影师用户名', db_index=True, unique=True)  | 
            
| 21 | 38 | 
                password = models.CharField(_(u'password'), max_length=255, blank=True, null=True, help_text=u'摄影师密码')  | 
            
| 22 | 39 | 
                encryption = models.CharField(_(u'encryption'), max_length=255, blank=True, null=True, help_text=u'摄影师密码')  | 
            
                @@ -30,6 +47,8 @@ class LensmanInfo(CreateUpdateMixin):  | 
            ||
| 30 | 47 | 
                 | 
            
| 31 | 48 | 
                balance = models.IntegerField(_(u'balance'), default=0, help_text=u'摄影师余额(分)')  | 
            
| 32 | 49 | 
                 | 
            
| 50 | 
                + user_status = models.IntegerField(_(u'user_status'), choices=USER_STATUS, default=UNVERIFIED)  | 
            |
| 51 | 
                +  | 
            |
| 33 | 52 | 
                signup_ip = models.CharField(_(u'signup_ip'), max_length=255, blank=True, null=True, help_text=_(u'注册IP'))  | 
            
| 34 | 53 | 
                login_ip = models.CharField(_(u'login_ip'), max_length=255, blank=True, null=True, help_text=_(u'登录IP'))  | 
            
| 35 | 54 | 
                login_at = models.DateTimeField(_(u'login_at'), blank=True, null=True, help_text=_(u'登录时间'))  | 
            
                @@ -41,6 +60,15 @@ class LensmanInfo(CreateUpdateMixin):  | 
            ||
| 41 | 60 | 
                def __unicode__(self):  | 
            
| 42 | 61 | 
                return unicode(self.pk)  | 
            
| 43 | 62 | 
                 | 
            
| 63 | 
                + @property  | 
            |
| 64 | 
                + def data(self):  | 
            |
| 65 | 
                +        return {
               | 
            |
| 66 | 
                + 'name': self.name,  | 
            |
| 67 | 
                + 'sex': self.sex,  | 
            |
| 68 | 
                + 'phone': self.phone,  | 
            |
| 69 | 
                + 'location': self.location,  | 
            |
| 70 | 
                + }  | 
            |
| 71 | 
                +  | 
            |
| 44 | 72 | 
                 | 
            
| 45 | 73 | 
                class LensmanLoginLogInfo(CreateUpdateMixin):  | 
            
| 46 | 74 | 
                SUCCESS = 0  | 
            
                @@ -91,6 +119,33 @@ class LensmanIncomeExpensesInfo(CreateUpdateMixin):  | 
            ||
| 91 | 119 | 
                return unicode(self.pk)  | 
            
| 92 | 120 | 
                 | 
            
| 93 | 121 | 
                 | 
            
| 122 | 
                +class WechatInfo(CreateUpdateMixin):  | 
            |
| 123 | 
                + MALE = 1  | 
            |
| 124 | 
                + FEMALE = 0  | 
            |
| 125 | 
                +  | 
            |
| 126 | 
                + SEX_TYPE = (  | 
            |
| 127 | 
                + (MALE, u'男'),  | 
            |
| 128 | 
                + (FEMALE, u'女'),  | 
            |
| 129 | 
                + )  | 
            |
| 130 | 
                +  | 
            |
| 131 | 
                + unionid = models.CharField(_(u'unionid'), max_length=255, blank=True, null=True, help_text=u'微信 Union ID')  | 
            |
| 132 | 
                + openids = JSONField(_(u'openids'), blank=True, null=True, help_text=u'微信 Open IDs')  | 
            |
| 133 | 
                + sex = models.IntegerField(_(u'sex'), choices=SEX_TYPE, default=MALE, help_text=u'用户性别')  | 
            |
| 134 | 
                + nickname = models.CharField(_(u'nickname'), max_length=255, blank=True, null=True, help_text=u'用户昵称')  | 
            |
| 135 | 
                + headimgurl = models.CharField(_(u'headimgurl'), max_length=255, blank=True, null=True, help_text=u'用户头像')  | 
            |
| 136 | 
                + country = models.CharField(_(u'country'), max_length=255, blank=True, null=True, help_text=u'用户国家')  | 
            |
| 137 | 
                + province = models.CharField(_(u'province'), max_length=255, blank=True, null=True, help_text=u'用户省份')  | 
            |
| 138 | 
                + city = models.CharField(_(u'city'), max_length=255, blank=True, null=True, help_text=u'用户城市')  | 
            |
| 139 | 
                + location = models.CharField(_(u'location'), max_length=255, blank=True, null=True, help_text=u'用户地址')  | 
            |
| 140 | 
                +  | 
            |
| 141 | 
                + class Meta:  | 
            |
| 142 | 
                + verbose_name = _(u'wechatinfo')  | 
            |
| 143 | 
                + verbose_name_plural = _(u'wechatinfo')  | 
            |
| 144 | 
                +  | 
            |
| 145 | 
                + def __unicode__(self):  | 
            |
| 146 | 
                + return unicode(self.pk)  | 
            |
| 147 | 
                +  | 
            |
| 148 | 
                +  | 
            |
| 94 | 149 | 
                class UserInfo(CreateUpdateMixin):  | 
            
| 95 | 150 | 
                APP_USER = 0  | 
            
| 96 | 151 | 
                WX_USER = 1  | 
            
                @@ -135,8 +190,7 @@ class UserInfo(CreateUpdateMixin):  | 
            ||
| 135 | 190 | 
                password = models.CharField(_(u'password'), max_length=255, blank=True, null=True, help_text=u'用户密码')  | 
            
| 136 | 191 | 
                # 微信授权用户  | 
            
| 137 | 192 | 
                wx_uid = models.CharField(_(u'wx_uid'), max_length=255, blank=True, null=True, help_text=u'微信唯一标识', db_index=True, unique=True)  | 
            
| 138 | 
                - unionid = models.CharField(_(u'unionid'), max_length=255, blank=True, null=True, help_text=u'微信 Union ID')  | 
            |
| 139 | 
                - # openid = models.CharField(_(u'openid'), max_length=255, blank=True, null=True, help_text=u'微信 Open ID')  | 
            |
| 193 | 
                + unionid = models.CharField(_(u'unionid'), max_length=255, blank=True, null=True, help_text=u'微信 Union ID', db_index=True, unique=True)  | 
            |
| 140 | 194 | 
                # 用户基本信息  | 
            
| 141 | 195 | 
                name = models.CharField(_(u'name'), max_length=255, blank=True, null=True, help_text=u'用户姓名')  | 
            
| 142 | 196 | 
                sex = models.IntegerField(_(u'sex'), choices=SEX_TYPE, default=MALE, help_text=u'用户性别')  | 
            
                @@ -130,8 +130,8 @@ def user_login_api(request):  | 
            ||
| 130 | 130 | 
                 | 
            
| 131 | 131 | 
                def wx_authorize_api(request):  | 
            
| 132 | 132 | 
                     user_id = request.POST.get('user_id', '')
               | 
            
| 133 | 
                -    wx_uid = request.POST.get('wx_uid', '')
               | 
            |
| 134 | 133 | 
                 | 
            
| 134 | 
                +    openid = wx_uid = request.POST.get('wx_uid', '')
               | 
            |
| 135 | 135 | 
                     unionid = request.POST.get('unionid', '')
               | 
            
| 136 | 136 | 
                 | 
            
| 137 | 137 | 
                     sex = request.POST.get('sex', 0)
               | 
            
                @@ -141,9 +141,9 @@ def wx_authorize_api(request):  | 
            ||
| 141 | 141 | 
                     province = request.POST.get('province', '')
               | 
            
| 142 | 142 | 
                     city = request.POST.get('city', '')
               | 
            
| 143 | 143 | 
                 | 
            
| 144 | 
                - # 判断 wx_uid 是否已经存在,如果已经存在,则直接返回改帐户信息  | 
            |
| 144 | 
                + # 判断 unionid 是否已经存在,如果已经存在,则直接返回改帐户信息  | 
            |
| 145 | 145 | 
                try:  | 
            
| 146 | 
                - user = UserInfo.objects.get(wx_uid=wx_uid)  | 
            |
| 146 | 
                + user = UserInfo.objects.get(unionid=unionid)  | 
            |
| 147 | 147 | 
                except UserInfo.DoesNotExist:  | 
            
| 148 | 148 | 
                user = None  | 
            
| 149 | 149 | 
                 | 
            
                @@ -163,7 +163,7 @@ def wx_authorize_api(request):  | 
            ||
| 163 | 163 | 
                'data': user.data,  | 
            
| 164 | 164 | 
                })  | 
            
| 165 | 165 | 
                 | 
            
| 166 | 
                - # wx_uid 不存在  | 
            |
| 166 | 
                + # unionid 不存在  | 
            |
| 167 | 167 | 
                # 判断 user_id 是否存在并且为分配用户,如果存在并且为分配用户,则直接在该帐户上更新,否则则直接创建帐户  | 
            
| 168 | 168 | 
                 | 
            
| 169 | 169 | 
                signup_ip, signup_at = ip_addr(request), tc.utc_datetime()  | 
            
                @@ -27,6 +27,7 @@ urlpatterns = [  | 
            ||
| 27 | 27 | 
                 | 
            
| 28 | 28 | 
                # 摄影师相关  | 
            
| 29 | 29 | 
                urlpatterns += [  | 
            
| 30 | 
                + url(r'^l/submit$', lensman_views.lensman_submit_api, name='lensman_submit_api'), # 摄影师登录  | 
            |
| 30 | 31 | 
                url(r'^l/login$', lensman_views.lensman_login_api, name='lensman_login_api'), # 摄影师登录  | 
            
| 31 | 32 | 
                url(r'^l/photos/upload$', lensman_views.lensman_upload_photo_api, name='lensman_upload_photo_api'), # 摄影师上传照片  | 
            
| 32 | 33 | 
                ]  | 
            
                @@ -104,7 +105,13 @@ urlpatterns += [  | 
            ||
| 104 | 105 | 
                url(r'^wx/balance_withdraw$', pay_views.wx_balance_withdraw_api, name='wx_balance_withdraw_api'), # 余额提现: 企业付款/现金红包  | 
            
| 105 | 106 | 
                ]  | 
            
| 106 | 107 | 
                 | 
            
| 107 | 
                -# 分享相关  | 
            |
| 108 | 
                +# 微信授权相关  | 
            |
| 109 | 
                +urlpatterns += [  | 
            |
| 110 | 
                + url(r'^get_openid$', wechat_views.get_openid, name='get_openid'),  | 
            |
| 111 | 
                + url(r'^to_redirect$', wechat_views.to_redirect, name='to_redirect'),  | 
            |
| 112 | 
                +]  | 
            |
| 113 | 
                +  | 
            |
| 114 | 
                +# 微信分享相关  | 
            |
| 108 | 115 | 
                urlpatterns += [  | 
            
| 109 | 116 | 
                url(r'^wx/jsapi_signature$', wechat_views.wx_jsapi_signature_api, name='wx_jsapi_signature_api'), # jsapi_signature  | 
            
| 110 | 117 | 
                ]  | 
            
                @@ -26,6 +26,35 @@ from utils.watermark_utils import watermark_wrap  | 
            ||
| 26 | 26 | 
                r = settings.REDIS_CACHE  | 
            
| 27 | 27 | 
                 | 
            
| 28 | 28 | 
                 | 
            
| 29 | 
                +def lensman_submit_api(request):  | 
            |
| 30 | 
                + """  | 
            |
| 31 | 
                + 摄影师信息提交  | 
            |
| 32 | 
                + :param request:  | 
            |
| 33 | 
                + :return:  | 
            |
| 34 | 
                + """  | 
            |
| 35 | 
                +    unionid = request.POST.get('unionid', '')
               | 
            |
| 36 | 
                +    phone = request.POST.get('phone', '')
               | 
            |
| 37 | 
                +  | 
            |
| 38 | 
                + if LensmanInfo.objects.filter(phone=phone).exclude(unionid=unionid).exists():  | 
            |
| 39 | 
                + return response(LensmanStatusCode.LENSMAN_PHONE_ALREADY_EXISTS)  | 
            |
| 40 | 
                +  | 
            |
| 41 | 
                +    fields = {
               | 
            |
| 42 | 
                +        'name': request.POST.get('name', ''),
               | 
            |
| 43 | 
                +        'sex': int(request.POST.get('sex', 1)),
               | 
            |
| 44 | 
                + 'phone': phone,  | 
            |
| 45 | 
                +        'location': request.POST.get('location', ''),
               | 
            |
| 46 | 
                + 'user_status': LensmanInfo.UNVERIFIED,  | 
            |
| 47 | 
                + }  | 
            |
| 48 | 
                +  | 
            |
| 49 | 
                + lensman, created = LensmanInfo.objects.get_or_create(unionid=unionid, defaults=fields)  | 
            |
| 50 | 
                + if not created:  | 
            |
| 51 | 
                + for key, value in fields.iteritems():  | 
            |
| 52 | 
                + setattr(lensman, key, value)  | 
            |
| 53 | 
                + lensman.save()  | 
            |
| 54 | 
                +  | 
            |
| 55 | 
                +    return response(200, 'Submit Success', u'提交成功', {})
               | 
            |
| 56 | 
                +  | 
            |
| 57 | 
                +  | 
            |
| 29 | 58 | 
                def lensman_login_api(request):  | 
            
| 30 | 59 | 
                """  | 
            
| 31 | 60 | 
                摄影师登录  | 
            
                @@ -0,0 +1,154 @@  | 
            ||
| 1 | 
                +{% load staticfiles %}
               | 
            |
| 2 | 
                +  | 
            |
| 3 | 
                +<!DOCTYPE html>  | 
            |
| 4 | 
                +<html lang="zh-CN">  | 
            |
| 5 | 
                +<head>  | 
            |
| 6 | 
                + <meta charset="utf-8">  | 
            |
| 7 | 
                + <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">  | 
            |
| 8 | 
                + <meta name="format-detection" content="telephone=no,email=no,address=no">  | 
            |
| 9 | 
                + <meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no">  | 
            |
| 10 | 
                + <title>摄影师授权</title>  | 
            |
| 11 | 
                +  | 
            |
| 12 | 
                + <link href="https://res.wx.qq.com/open/libs/weui/0.4.3/weui.min.css" rel="stylesheet" type="text/css" />  | 
            |
| 13 | 
                +  | 
            |
| 14 | 
                + <style>  | 
            |
| 15 | 
                +        input:required:invalid {
               | 
            |
| 16 | 
                + color: #E64340;  | 
            |
| 17 | 
                + }  | 
            |
| 18 | 
                +        input:required:valid {
               | 
            |
| 19 | 
                + color: rgba(0, 0, 0);  | 
            |
| 20 | 
                + }  | 
            |
| 21 | 
                +  | 
            |
| 22 | 
                + </style>  | 
            |
| 23 | 
                +</head>  | 
            |
| 24 | 
                +<body>  | 
            |
| 25 | 
                + <div class="container" >  | 
            |
| 26 | 
                + <div class="weui_cells weui_cells_form">  | 
            |
| 27 | 
                + <div class="weui_cell">  | 
            |
| 28 | 
                + <div class="weui_cell_hd"><label for="" class="weui_label">姓名</label></div>  | 
            |
| 29 | 
                + <div class="weui_cell_bd weui_cell_primary">  | 
            |
| 30 | 
                +                    <input id="name" class="weui_input" type="text" value="{{ lensman_info.name }}" placeholder="请输入姓名">
               | 
            |
| 31 | 
                + </div>  | 
            |
| 32 | 
                + </div>  | 
            |
| 33 | 
                + <div class="weui_cell weui_cell_select weui_select_after">  | 
            |
| 34 | 
                + <div class="weui_cell_hd"><label for="" class="weui_label">性别</label></div>  | 
            |
| 35 | 
                + <div class="weui_cell_bd weui_cell_primary">  | 
            |
| 36 | 
                + <select id="sex" class="weui_select" name="select">  | 
            |
| 37 | 
                +                        <option value="1" {% ifequal lensman_info.sex 1 %}selected{% endifequal %}>男</option>
               | 
            |
| 38 | 
                +                        <option value="0" {% ifequal lensman_info.sex 0 %}selected{% endifequal %}>女</option>
               | 
            |
| 39 | 
                + </select>  | 
            |
| 40 | 
                + </div>  | 
            |
| 41 | 
                + </div>  | 
            |
| 42 | 
                + <div class="weui_cell">  | 
            |
| 43 | 
                + <div class="weui_cell_hd"><label for="" class="weui_label">手机号</label></div>  | 
            |
| 44 | 
                + <div class="weui_cell_bd weui_cell_primary">  | 
            |
| 45 | 
                +                    <input id="phone" class="weui_input" type="text" required="required" pattern="[0-9]{11}" value="{{ lensman_info.phone }}" placeholder="请输入手机号">
               | 
            |
| 46 | 
                + </div>  | 
            |
| 47 | 
                + </div>  | 
            |
| 48 | 
                + <div class="weui_cell">  | 
            |
| 49 | 
                + <div class="weui_cell_hd"><label for="" class="weui_label">地址</label></div>  | 
            |
| 50 | 
                + <div class="weui_cell_bd weui_cell_primary">  | 
            |
| 51 | 
                +                    <input id="location" class="weui_input" type="text" value="{{ lensman_info.location }}" placeholder="请输入地址">
               | 
            |
| 52 | 
                + </div>  | 
            |
| 53 | 
                + </div>  | 
            |
| 54 | 
                + </div>  | 
            |
| 55 | 
                +  | 
            |
| 56 | 
                + <br>  | 
            |
| 57 | 
                +  | 
            |
| 58 | 
                + <button id="submit" class="weui_btn weui_btn_warn">确认</button>  | 
            |
| 59 | 
                +  | 
            |
| 60 | 
                + <div class="weui_dialog_alert" id="dialog" style="display: none">  | 
            |
| 61 | 
                + <div class="weui_mask"></div>  | 
            |
| 62 | 
                + <div class="weui_dialog">  | 
            |
| 63 | 
                + <div class="weui_dialog_hd"><strong id="title" class="weui_dialog_title">弹窗标题</strong></div>  | 
            |
| 64 | 
                + <div id="content" class="weui_dialog_bd">弹窗内容,告知当前页面信息等</div>  | 
            |
| 65 | 
                + <div class="weui_dialog_ft">  | 
            |
| 66 | 
                + <a href="javascript:;" class="weui_btn_dialog primary">确定</a>  | 
            |
| 67 | 
                + </div>  | 
            |
| 68 | 
                + </div>  | 
            |
| 69 | 
                + </div>  | 
            |
| 70 | 
                +  | 
            |
| 71 | 
                + <div id="toast" style="display: none;">  | 
            |
| 72 | 
                + <div class="weui_mask_transparent"></div>  | 
            |
| 73 | 
                + <div class="weui_toast">  | 
            |
| 74 | 
                + <i class="weui_icon_toast"></i>  | 
            |
| 75 | 
                + <p class="weui_toast_content">已完成</p>  | 
            |
| 76 | 
                + </div>  | 
            |
| 77 | 
                + </div>  | 
            |
| 78 | 
                + </div>  | 
            |
| 79 | 
                +  | 
            |
| 80 | 
                + <script src="//cdn.bootcss.com/zepto/1.1.6/zepto.min.js"></script>  | 
            |
| 81 | 
                + <script>  | 
            |
| 82 | 
                +        $(function() {
               | 
            |
| 83 | 
                +            function getURLParameter(name) {
               | 
            |
| 84 | 
                +              return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search) || [null, ''])[1].replace(/\+/g, '%20')) || null;
               | 
            |
| 85 | 
                + }  | 
            |
| 86 | 
                +  | 
            |
| 87 | 
                +            function show_error_dialog(title, content) {
               | 
            |
| 88 | 
                +                $('#dialog #title').text(title);
               | 
            |
| 89 | 
                +                $('#dialog #content').text(content);
               | 
            |
| 90 | 
                +                $('#dialog').show();
               | 
            |
| 91 | 
                + }  | 
            |
| 92 | 
                +  | 
            |
| 93 | 
                +            function data_check() {
               | 
            |
| 94 | 
                +                var unionid = getURLParameter('unionid');
               | 
            |
| 95 | 
                +                if (!unionid) {
               | 
            |
| 96 | 
                +                    show_error_dialog('微信授权', '微信授权失败,请重新打开页面');
               | 
            |
| 97 | 
                + return false;  | 
            |
| 98 | 
                + }  | 
            |
| 99 | 
                +  | 
            |
| 100 | 
                +                var name = $('#name').val();
               | 
            |
| 101 | 
                +                if (!name) {
               | 
            |
| 102 | 
                +                    show_error_dialog('姓名', '姓名错误,请检查重新输入');
               | 
            |
| 103 | 
                + return false;  | 
            |
| 104 | 
                + }  | 
            |
| 105 | 
                +  | 
            |
| 106 | 
                +                var phone_valid = $('#phone').is(':valid');
               | 
            |
| 107 | 
                +                if (!phone_valid) {
               | 
            |
| 108 | 
                +                    show_error_dialog('手机号', '手机号错误,请检查重新输入');
               | 
            |
| 109 | 
                + return false;  | 
            |
| 110 | 
                + }  | 
            |
| 111 | 
                +  | 
            |
| 112 | 
                +                var location = $('#location').val();
               | 
            |
| 113 | 
                +                if (!location) {
               | 
            |
| 114 | 
                +                    show_error_dialog('地址', '地址错误,请检查重新输入');
               | 
            |
| 115 | 
                + return false;  | 
            |
| 116 | 
                + }  | 
            |
| 117 | 
                +  | 
            |
| 118 | 
                +                return {
               | 
            |
| 119 | 
                + unionid: unionid,  | 
            |
| 120 | 
                + name: name,  | 
            |
| 121 | 
                +                    sex: $('#sex option:checked').val(),
               | 
            |
| 122 | 
                +                    phone: $('#phone').val(),
               | 
            |
| 123 | 
                + location: location,  | 
            |
| 124 | 
                + }  | 
            |
| 125 | 
                + }  | 
            |
| 126 | 
                +  | 
            |
| 127 | 
                +            $('#submit').click(function () {
               | 
            |
| 128 | 
                + var check_result = data_check();  | 
            |
| 129 | 
                +                if (check_result){
               | 
            |
| 130 | 
                +                    $.ajax({
               | 
            |
| 131 | 
                + type: 'POST',  | 
            |
| 132 | 
                + url: 'l/submit',  | 
            |
| 133 | 
                + data: check_result,  | 
            |
| 134 | 
                +                        success: function(data) {
               | 
            |
| 135 | 
                +                            if (data.status == 200) {
               | 
            |
| 136 | 
                +                                $('#toast').show();
               | 
            |
| 137 | 
                +                                setTimeout(function () {
               | 
            |
| 138 | 
                +                                    $('#toast').hide();
               | 
            |
| 139 | 
                + }, 1000);  | 
            |
| 140 | 
                +                            } else {
               | 
            |
| 141 | 
                +                                show_error_dialog('错误', data.description);
               | 
            |
| 142 | 
                + }  | 
            |
| 143 | 
                + }  | 
            |
| 144 | 
                + })  | 
            |
| 145 | 
                + }  | 
            |
| 146 | 
                + });  | 
            |
| 147 | 
                +  | 
            |
| 148 | 
                +            $('#dialog .weui_btn_dialog').click(function () {
               | 
            |
| 149 | 
                +                $('#dialog').hide();
               | 
            |
| 150 | 
                + })  | 
            |
| 151 | 
                + });  | 
            |
| 152 | 
                + </script>  | 
            |
| 153 | 
                +</body>  | 
            |
| 154 | 
                +</html>  | 
            
                @@ -2,6 +2,8 @@  | 
            ||
| 2 | 2 | 
                 | 
            
| 3 | 3 | 
                from django.shortcuts import render  | 
            
| 4 | 4 | 
                 | 
            
| 5 | 
                +from account.models import LensmanInfo  | 
            |
| 6 | 
                +  | 
            |
| 5 | 7 | 
                 | 
            
| 6 | 8 | 
                def user_agreement(request):  | 
            
| 7 | 9 | 
                     return render(request, 'page/user_agreement.html', {})
               | 
            
                @@ -9,3 +11,16 @@ def user_agreement(request):  | 
            ||
| 9 | 11 | 
                 | 
            
| 10 | 12 | 
                def contact_us(request):  | 
            
| 11 | 13 | 
                     return render(request, 'page/contact_us.html', {})
               | 
            
| 14 | 
                +  | 
            |
| 15 | 
                +  | 
            |
| 16 | 
                +def lensman_oauth(request):  | 
            |
| 17 | 
                +    unionid = request.GET.get('unionid', '')
               | 
            |
| 18 | 
                +  | 
            |
| 19 | 
                + try:  | 
            |
| 20 | 
                + lensman = LensmanInfo.objects.get(unionid=unionid)  | 
            |
| 21 | 
                + except LensmanInfo.DoesNotExist:  | 
            |
| 22 | 
                + lensman = None  | 
            |
| 23 | 
                +  | 
            |
| 24 | 
                +    return render(request, 'page/lensman_oauth.html', {
               | 
            |
| 25 | 
                + 'lensman_info': lensman and lensman.data  | 
            |
| 26 | 
                + })  | 
            
                @@ -23,6 +23,7 @@ from rest_framework import routers  | 
            ||
| 23 | 23 | 
                 | 
            
| 24 | 24 | 
                from account import views as account_views  | 
            
| 25 | 25 | 
                from group import views as group_views  | 
            
| 26 | 
                +from group import lensman_views  | 
            |
| 26 | 27 | 
                from page import views as page_views  | 
            
| 27 | 28 | 
                from photo import views as photo_views  | 
            
| 28 | 29 | 
                from website import views as website_views  | 
            
                @@ -65,6 +66,8 @@ urlpatterns += [  | 
            ||
| 65 | 66 | 
                urlpatterns += [  | 
            
| 66 | 67 | 
                url(r'^page/user_agreement$', page_views.user_agreement, name='user_agreement'), # 用户协议页面  | 
            
| 67 | 68 | 
                url(r'^page/contact_us$', page_views.contact_us, name='contact_us'), # 联系我们页面  | 
            
| 69 | 
                +  | 
            |
| 70 | 
                + url(r'^page/lensman$', page_views.lensman_oauth, name='lensman_oauth'), # 摄影师授权页面  | 
            |
| 68 | 71 | 
                ]  | 
            
| 69 | 72 | 
                 | 
            
| 70 | 73 | 
                urlpatterns += [  | 
            
                @@ -75,6 +78,11 @@ urlpatterns += [  | 
            ||
| 75 | 78 | 
                url(r'^termofservice$', website_views.pai2_termofservice, name='pai2_termofservice'), # 官网服务条款  | 
            
| 76 | 79 | 
                ]  | 
            
| 77 | 80 | 
                 | 
            
| 81 | 
                +# 摄影师相关  | 
            |
| 82 | 
                +urlpatterns += [  | 
            |
| 83 | 
                + url(r'^page/l/submit$', lensman_views.lensman_submit_api, name='lensman_submit_api'), # 摄影师登录  | 
            |
| 84 | 
                +]  | 
            |
| 85 | 
                +  | 
            |
| 78 | 86 | 
                # Wire up our API using automatic URL routing.  | 
            
| 79 | 87 | 
                # Additionally, we include login URLs for the browsable API.  | 
            
| 80 | 88 | 
                urlpatterns += [  | 
            
                @@ -11,12 +11,14 @@ django-logit==1.0.2  | 
            ||
| 11 | 11 | 
                django-multidomain==1.1.4  | 
            
| 12 | 12 | 
                django-shortuuidfield==0.1.3  | 
            
| 13 | 13 | 
                djangorestframework==3.3.1  | 
            
| 14 | 
                +furl==0.4.95  | 
            |
| 14 | 15 | 
                hiredis==0.2.0  | 
            
| 15 | 16 | 
                ipdb==0.8.1  | 
            
| 16 | 17 | 
                ipython==4.0.0  | 
            
| 17 | 18 | 
                jsonfield==1.0.3  | 
            
| 18 | 19 | 
                kkconst==1.1.2  | 
            
| 19 | 20 | 
                pep8==1.6.2  | 
            
| 21 | 
                +pysnippets==1.0.2  | 
            |
| 20 | 22 | 
                pytz==2015.7  | 
            
| 21 | 23 | 
                records==0.4.3  | 
            
| 22 | 24 | 
                redis==2.10.5  | 
            
                @@ -19,6 +19,8 @@ class LensmanStatusCode(BaseStatusCode):  | 
            ||
| 19 | 19 | 
                LENSMAN_NOT_FOUND = StatusCodeField(400001, u'Lensman Not Found', description=u'摄影师不存在')  | 
            
| 20 | 20 | 
                LENSMAN_PASSWORD_ERROR = StatusCodeField(400002, u'Lensman Password Error', description=u'摄影师密码错误')  | 
            
| 21 | 21 | 
                 | 
            
| 22 | 
                + LENSMAN_PHONE_ALREADY_EXISTS = StatusCodeField(400005, u'Lensman Phone Already Exists', description=u'手机号已经存在')  | 
            |
| 23 | 
                +  | 
            |
| 22 | 24 | 
                 | 
            
| 23 | 25 | 
                class UserStatusCode(BaseStatusCode):  | 
            
| 24 | 26 | 
                """ 用户相关错误码 4001xx """  | 
            
                @@ -1,10 +1,16 @@  | 
            ||
| 1 | 1 | 
                # -*- coding: utf-8 -*-  | 
            
| 2 | 2 | 
                 | 
            
| 3 | 3 | 
                import time  | 
            
| 4 | 
                +import urllib  | 
            |
| 4 | 5 | 
                 | 
            
| 6 | 
                +import requests  | 
            |
| 5 | 7 | 
                import shortuuid  | 
            
| 8 | 
                +from CodeConvert import CodeConvert as cc  | 
            |
| 6 | 9 | 
                from django.conf import settings  | 
            
| 10 | 
                +from django.shortcuts import redirect  | 
            |
| 11 | 
                +from furl import furl  | 
            |
| 7 | 12 | 
                from json_response import auto_response  | 
            
| 13 | 
                +from pysnippets import dictsnippets as dsnippets  | 
            |
| 8 | 14 | 
                from wechatpy import WeChatClient  | 
            
| 9 | 15 | 
                 | 
            
| 10 | 16 | 
                 | 
            
                @@ -13,6 +19,33 @@ WECHAT = settings.WECHAT  | 
            ||
| 13 | 19 | 
                 JSAPI = WECHAT.get('JSAPI', {})
               | 
            
| 14 | 20 | 
                 | 
            
| 15 | 21 | 
                 | 
            
| 22 | 
                +def get_openid(request):  | 
            |
| 23 | 
                +    scope = request.GET.get('scope', 'snsapi_userinfo')
               | 
            |
| 24 | 
                +    redirect_url = request.GET.get('redirect_url', '')
               | 
            |
| 25 | 
                +    default_url = request.GET.get('default_url', '')
               | 
            |
| 26 | 
                +  | 
            |
| 27 | 
                + if request.weixin:  | 
            |
| 28 | 
                + authorize_url = settings.WECHAT_GET_CODE_USERINFO if scope == 'snsapi_userinfo' else settings.WECHAT_GET_CODE_BASE  | 
            |
| 29 | 
                + get_code_url = authorize_url % (JSAPI['appID'], urllib.quote_plus(settings.WECHAT_REDIRECT_URI), urllib.quote_plus(redirect_url))  | 
            |
| 30 | 
                + return redirect(get_code_url)  | 
            |
| 31 | 
                +  | 
            |
| 32 | 
                + return redirect(default_url if default_url else redirect_url)  | 
            |
| 33 | 
                +  | 
            |
| 34 | 
                +  | 
            |
| 35 | 
                +def to_redirect(request):  | 
            |
| 36 | 
                +    code = request.GET.get('code', '')
               | 
            |
| 37 | 
                +    state = request.GET.get('state', '')
               | 
            |
| 38 | 
                +  | 
            |
| 39 | 
                + access_info = requests.get(settings.WECHAT_GET_OAUTH2_ACCESS_TOKEN % (JSAPI['appID'], JSAPI['appsecret'], code), verify=False).json()  | 
            |
| 40 | 
                +    unionid, openid, access_token = access_info.get('unionid', ''), access_info.get('openid', ''), access_info.get('access_token', '')
               | 
            |
| 41 | 
                +  | 
            |
| 42 | 
                + res = requests.get(settings.WECHAT_GET_USERINFO % (access_token, openid), verify=False)  | 
            |
| 43 | 
                + res.encoding = 'utf-8'  | 
            |
| 44 | 
                + userinfo = res.json()  | 
            |
| 45 | 
                +  | 
            |
| 46 | 
                + return redirect(furl(state).add(cc.Convert2Utf8(dsnippets.filter(userinfo, ['unionid', 'openid', 'nickname', 'headimgurl']))).url)  | 
            |
| 47 | 
                +  | 
            |
| 48 | 
                +  | 
            |
| 16 | 49 | 
                @auto_response  | 
            
| 17 | 50 | 
                def wx_jsapi_signature_api(request):  | 
            
| 18 | 51 | 
                     url = request.GET.get('url', '')
               |